mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
4dabfa5de7
into mysql.com:/home/kent/bk/main/mysql-5.1 BUILD/Makefile.am: Auto merged BitKeeper/deleted/.del-ArrayFifoList.hpp~7036ae04dd7e7bd2: Auto merged BitKeeper/deleted/.del-ArrayList.hpp~44695d09b1a02179: Auto merged BitKeeper/deleted/.del-DbtupLCP.cpp~855b1ed3fbc86a42: Auto merged BitKeeper/deleted/.del-DbtupSystemRestart.cpp~15b54d7e4e75d2d: Auto merged BitKeeper/deleted/.del-DbtupUndoLog.cpp~5a2ef6e86b1404e9: Auto merged Makefile.am: Auto merged BitKeeper/deleted/.del-Makefile.am~2: Auto merged BitKeeper/deleted/.del-Makefile.am~ab5c84d46412dc2e: Auto merged BitKeeper/deleted/.del-Makefile.am~abb265028eb9b6a7: Auto merged BitKeeper/deleted/.del-Makefile.am~de166d6fcac3b9b6: Auto merged BitKeeper/deleted/.del-Makefile.am~e5b911533dad2713: Auto merged BitKeeper/deleted/.del-Makefile.am~ead19441cc5ff35c: Auto merged BitKeeper/deleted/.del-Makefile.am~f87185e232d7c4f: Auto merged BitKeeper/deleted/.del-Makefile.in: Auto merged BitKeeper/deleted/.del-MemoryChannelOSE.hpp: Auto merged BitKeeper/deleted/.del-MetaData.cpp~146ae9865dd35829: Auto merged BitKeeper/deleted/.del-MetaData.hpp~538342afcd8ac53c: Auto merged BitKeeper/deleted/.del-NdbCondition.c~ad83464328ab37af: Auto merged BitKeeper/deleted/.del-NdbCondition.c~ee56562abdd718cf: Auto merged BitKeeper/deleted/.del-NdbConditionOSE.h~455dd2c29c2e6344: Auto merged BitKeeper/deleted/.del-NdbDaemon.c~3b8101f376b28df: Auto merged BitKeeper/deleted/.del-NdbEnv.c~207f9ce9754c9e8a: Auto merged BitKeeper/deleted/.del-NdbEnv.c~bb6fe7572d45288a: Auto merged BitKeeper/deleted/.del-NdbErrHnd.cpp: Auto merged BitKeeper/deleted/.del-NdbHost.c~2c29816c77396d7b: Auto merged BitKeeper/deleted/.del-NdbHost.c~cf18d6b3c825180c: Auto merged BitKeeper/deleted/.del-NdbMem.c~6285b159985d46da: Auto merged BitKeeper/deleted/.del-NdbMem.c~6c2b317c1ce230ab: Auto merged BitKeeper/deleted/.del-NdbMem_SoftOse.cpp~9c61e311ec168d44: Auto merged BitKeeper/deleted/.del-NdbMutex.c~768131269bccca10: Auto merged BitKeeper/deleted/.del-NdbMutex.c~f4bdd19be08b84ab: Auto merged BitKeeper/deleted/.del-NdbOut.cpp~8caa99a0d729540c: Auto merged BitKeeper/deleted/.del-NdbSleep.c~b643ea3e7103eb62: Auto merged BitKeeper/deleted/.del-NdbSleep.c~b88fbc5b140de10d: Auto merged BitKeeper/deleted/.del-NdbTCP.c~1e9f416992352f6d: Auto merged BitKeeper/deleted/.del-NdbTCP.c~b09cdcbef3ea2c57: Auto merged BitKeeper/deleted/.del-NdbThread.c~2fe1fa5f47801772: Auto merged BitKeeper/deleted/.del-NdbThread.c~fe71a67b5c3a4724: Auto merged BitKeeper/deleted/.del-NdbTick.c~aa6385567216509d: Auto merged BitKeeper/deleted/.del-NdbTick.c~b76feba2cf1493d1: Auto merged BitKeeper/deleted/.del-OSE_Receiver.cpp: Auto merged BitKeeper/deleted/.del-OSE_Receiver.hpp: Auto merged BitKeeper/deleted/.del-OSE_Signals.hpp: Auto merged BitKeeper/deleted/.del-OSE_Transporter.cpp: Auto merged BitKeeper/deleted/.del-OSE_Transporter.hpp: Auto merged BitKeeper/deleted/.del-TraceNdbApi.hpp~7a7f0ae5b70358bc: Auto merged BitKeeper/deleted/.del-VerifyNdbApi.hpp~f417f78f7cd05935: Auto merged BitKeeper/deleted/.del-bcd.h~81fbfcc1530534da: Auto merged BitKeeper/deleted/.del-config-os2.h~a16b51851ddd317b: Auto merged BitKeeper/deleted/.del-dbGenerator.c~7509c19f70cad0bf: Auto merged BitKeeper/deleted/.del-dbGenerator.h~63f1aeb98260bcb7: Auto merged BitKeeper/deleted/.del-dbGenerator.h~e1aaa6725999d458: Auto merged BitKeeper/deleted/.del-dbPopulate.c~5dcff1c99783d83b: Auto merged BitKeeper/deleted/.del-dbPopulate.h~229a894b59d4da73: Auto merged BitKeeper/deleted/.del-ha_berkeley.cc: Auto merged BitKeeper/deleted/.del-ha_berkeley.h: Auto merged BitKeeper/deleted/.del-localDbPrepare.c~33a2c46afc8fac9a: Auto merged BitKeeper/deleted/.del-macros.h~58097d584e29b5df: Auto merged BitKeeper/deleted/.del-macros.h~742871fab0681964: Auto merged BitKeeper/deleted/.del-mainGenerator.c~2d1c8016f72b2517: Auto merged BitKeeper/deleted/.del-mainPopulate.c~37def9a44980b8ec: Auto merged BitKeeper/deleted/.del-mgmapi_logevent.cpp~f1e7cf3e70edc4: Auto merged BitKeeper/deleted/.del-mmslist.cpp: Auto merged BitKeeper/deleted/.del-my_lread.c: Auto merged BitKeeper/deleted/.del-my_lwrite.c: Auto merged BitKeeper/deleted/.del-my_os2cond.c~e3b520af1c371bb5: Auto merged BitKeeper/deleted/.del-my_os2dirsrch.c~4e2479b2abb2eb5a: Auto merged BitKeeper/deleted/.del-my_os2dirsrch.h~5011cbc657537d0: Auto merged BitKeeper/deleted/.del-my_os2dlfcn.c~6d94b488717683dd: Auto merged BitKeeper/deleted/.del-my_os2dlfcn.h0~eae8edb8555eff87: Auto merged BitKeeper/deleted/.del-my_os2file64.c~251fb8a1e950c31b: Auto merged BitKeeper/deleted/.del-my_os2thread.c~65dca991548cec2a: Auto merged BitKeeper/deleted/.del-my_os2tls.c~58ade7a0f70ad5ea: Auto merged BitKeeper/deleted/.del-mysqlmanager-pwgen.c~d8f5f91ec54432b9: Auto merged BitKeeper/deleted/.del-mysqlmanager.c~e97636d71145a0b: Auto merged BitKeeper/deleted/.del-mysqlmanagerc.c~4f6e3499e68508f6: Auto merged BitKeeper/deleted/.del-ndb_error.hpp~24468bb7f20a0b41: Auto merged BitKeeper/deleted/.del-ndb_error.hpp~45a2fef922beae3: Auto merged BitKeeper/deleted/.del-ndb_schema.hpp~de9c21185d6bfe4e: Auto merged BitKeeper/deleted/.del-ndbapi_async.cpp~319189569fb659ec: Auto merged BitKeeper/deleted/.del-ndbapi_async1.cpp~2995dac9b963a0d: Auto merged BitKeeper/deleted/.del-ndbapi_event.cpp~c5d949802966180: Auto merged BitKeeper/deleted/.del-ndbapi_retries.cpp~7301496d8c1c310a: Auto merged BitKeeper/deleted/.del-ndbapi_scan.cpp~14ed2aa9a5d9e597: Auto merged BitKeeper/deleted/.del-ndbapi_simple.cpp~80962179f3c2f5b8: Auto merged BitKeeper/deleted/.del-ndbapi_simple_index.cpp~4b95a4d71808b5b6: Auto merged BitKeeper/deleted/.del-print-limit-table~b8e808031daa3758: Auto merged BitKeeper/deleted/.del-raid.cc~488f5fa6538394e1: Auto merged BitKeeper/deleted/.del-raid.h~2d2503a66b128ac6: Auto merged BitKeeper/deleted/.del-raid2.c~fe7aea5fb4b9748c: Auto merged BitKeeper/deleted/.del-sql_manager.h: Auto merged BitKeeper/deleted/.del-testData.h~696038ea2623a90b: Auto merged BitKeeper/deleted/.del-testData.h~898b71d7c639319e: Auto merged BitKeeper/deleted/.del-testDefinitions.h~f18a4553579a3725: Auto merged BitKeeper/deleted/.del-userHandle.h~3275bb415e1ca2c2: Auto merged BitKeeper/deleted/.del-userHandle.h~ec22dc7a7ed2f81b: Auto merged BitKeeper/deleted/.del-userInterface.cpp~82ee612ab14b3d48: Auto merged BitKeeper/deleted/.del-userInterface.c~92a20032f7d1e91: Auto merged BitKeeper/deleted/.del-userInterface.h~1f76ad2f28b283fd: Auto merged BitKeeper/deleted/.del-userInterface.h~49139f029bbdaabc: Auto merged BitKeeper/deleted/.del-userTransaction.c~438012ecc761b776: Auto merged BitKeeper/deleted/.del-userTransaction.c~f50661b4f54b0bdd: Auto merged BitKeeper/deleted/.del-utv.h~f64af026b9705ebb: Auto merged BitKeeper/deleted/.del-vcdrfunc.h~85803875180684cd: Auto merged BitKeeper/deleted/.del-waiter.cpp~b188e4bfddf2cf98: Auto merged Docs/Makefile.am: Auto merged client/Makefile.am: Auto merged client/client_priv.h: Auto merged client/get_password.c: Auto merged client/mysql.cc: Auto merged client/mysql_upgrade.c: Auto merged client/mysqladmin.cc: Auto merged client/mysqlbinlog.cc: Auto merged client/mysqlcheck.c: Auto merged client/mysqldump.c: Auto merged client/mysqlimport.c: Auto merged client/mysqlshow.c: Auto merged client/mysqltest.c: Auto merged dbug/Makefile.am: Auto merged extra/Makefile.am: Auto merged extra/comp_err.c: Auto merged extra/perror.c: Auto merged extra/replace.c: Auto merged extra/resolveip.c: Auto merged include/Makefile.am: Auto merged include/base64.h: Auto merged include/config-netware.h: Auto merged include/config-win.h: Auto merged include/decimal.h: Auto merged include/errmsg.h: Auto merged include/ft_global.h: Auto merged include/heap.h: Auto merged include/m_ctype.h: Auto merged include/m_string.h: Auto merged include/my_base.h: Auto merged include/my_bitmap.h: Auto merged include/my_dbug.h: Auto merged include/my_global.h: Auto merged include/my_net.h: Auto merged include/my_no_pthread.h: Auto merged include/my_nosys.h: Auto merged include/my_pthread.h: Auto merged include/my_sys.h: Auto merged include/my_time.h: Auto merged include/my_tree.h: Auto merged include/my_xml.h: Auto merged include/myisam.h: Auto merged include/myisammrg.h: Auto merged include/mysql.h: Auto merged include/mysql_com.h: Auto merged include/mysys_err.h: Auto merged include/queues.h: Auto merged include/thr_alarm.h: Auto merged include/thr_lock.h: Auto merged include/violite.h: Auto merged libmysqld/Makefile.am: Auto merged libmysqld/emb_qcache.cc: Auto merged libmysqld/embedded_priv.h: Auto merged libmysqld/examples/Makefile.am: Auto merged libmysqld/libmysqld.c: Auto merged mysql-test/Makefile.am: Auto merged mysys/Makefile.am: Auto merged mysys/array.c: Auto merged mysys/base64.c: Auto merged mysys/charset-def.c: Auto merged mysys/default.c: Auto merged mysys/default_modify.c: Auto merged mysys/errors.c: Auto merged mysys/hash.c: Auto merged mysys/mf_dirname.c: Auto merged mysys/mf_format.c: Auto merged mysys/mf_iocache.c: Auto merged mysys/mf_iocache2.c: Auto merged mysys/mf_keycache.c: Auto merged mysys/mf_pack.c: Auto merged mysys/mf_path.c: Auto merged mysys/mf_tempdir.c: Auto merged mysys/mf_tempfile.c: Auto merged mysys/my_access.c: Auto merged mysys/my_alloc.c: Auto merged mysys/my_append.c: Auto merged mysys/my_bit.c: Auto merged mysys/my_bitmap.c: Auto merged mysys/my_clock.c: Auto merged mysys/my_compress.c: Auto merged mysys/my_copy.c: Auto merged mysys/my_create.c: Auto merged mysys/my_dup.c: Auto merged mysys/my_error.c: Auto merged mysys/my_file.c: Auto merged mysys/my_gethostbyname.c: Auto merged mysys/my_getopt.c: Auto merged mysys/my_getwd.c: Auto merged mysys/my_handler.c: Auto merged mysys/my_init.c: Auto merged mysys/my_lib.c: Auto merged mysys/my_lock.c: Auto merged mysys/my_malloc.c: Auto merged mysys/my_mkdir.c: Auto merged mysys/my_mmap.c: Auto merged mysys/my_net.c: Auto merged mysys/my_once.c: Auto merged mysys/my_open.c: Auto merged mysys/my_pread.c: Auto merged mysys/my_pthread.c: Auto merged mysys/my_redel.c: Auto merged mysys/my_rename.c: Auto merged mysys/my_seek.c: Auto merged mysys/my_sleep.c: Auto merged mysys/my_static.c: Auto merged mysys/my_symlink2.c: Auto merged mysys/my_thr_init.c: Auto merged mysys/mysys_priv.h: Auto merged mysys/ptr_cmp.c: Auto merged mysys/queues.c: Auto merged mysys/safemalloc.c: Auto merged mysys/string.c: Auto merged mysys/test_dir.c: Auto merged mysys/testhash.c: Auto merged mysys/thr_alarm.c: Auto merged mysys/thr_lock.c: Auto merged mysys/thr_mutex.c: Auto merged regex/Makefile.am: Auto merged scripts/Makefile.am: Auto merged server-tools/instance-manager/Makefile.am: Auto merged server-tools/instance-manager/buffer.cc: Auto merged server-tools/instance-manager/command.cc: Auto merged server-tools/instance-manager/command.h: Auto merged server-tools/instance-manager/commands.cc: Auto merged server-tools/instance-manager/commands.h: Auto merged server-tools/instance-manager/guardian.cc: Auto merged server-tools/instance-manager/guardian.h: Auto merged server-tools/instance-manager/instance.cc: Auto merged server-tools/instance-manager/instance.h: Auto merged server-tools/instance-manager/instance_map.cc: Auto merged server-tools/instance-manager/instance_map.h: Auto merged server-tools/instance-manager/instance_options.cc: Auto merged server-tools/instance-manager/instance_options.h: Auto merged server-tools/instance-manager/listener.cc: Auto merged server-tools/instance-manager/listener.h: Auto merged server-tools/instance-manager/log.cc: Auto merged server-tools/instance-manager/log.h: Auto merged server-tools/instance-manager/manager.cc: Auto merged server-tools/instance-manager/manager.h: Auto merged server-tools/instance-manager/messages.cc: Auto merged server-tools/instance-manager/mysql_connection.cc: Auto merged server-tools/instance-manager/mysql_connection.h: Auto merged server-tools/instance-manager/mysql_manager_error.h: Auto merged server-tools/instance-manager/mysqlmanager.cc: Auto merged server-tools/instance-manager/options.cc: Auto merged server-tools/instance-manager/options.h: Auto merged server-tools/instance-manager/parse.cc: Auto merged server-tools/instance-manager/parse.h: Auto merged server-tools/instance-manager/parse_output.cc: Auto merged server-tools/instance-manager/parse_output.h: Auto merged server-tools/instance-manager/priv.cc: Auto merged server-tools/instance-manager/priv.h: Auto merged server-tools/instance-manager/protocol.cc: Auto merged server-tools/instance-manager/protocol.h: Auto merged server-tools/instance-manager/thread_registry.cc: Auto merged server-tools/instance-manager/thread_registry.h: Auto merged server-tools/instance-manager/user_map.cc: Auto merged server-tools/instance-manager/user_map.h: Auto merged sql/Makefile.am: Auto merged sql/discover.cc: Auto merged sql/field.cc: Auto merged sql/field.h: Auto merged sql/field_conv.cc: Auto merged sql/filesort.cc: Auto merged sql/gen_lex_hash.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/ha_ndbcluster.h: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/hostname.cc: Auto merged sql/init.cc: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_create.cc: Auto merged sql/item_create.h: Auto merged sql/item_func.cc: Auto merged sql/item_func.h: Auto merged sql/item_geofunc.cc: Auto merged sql/item_geofunc.h: Auto merged sql/item_row.cc: Auto merged sql/item_row.h: Auto merged sql/item_strfunc.cc: Auto merged sql/item_strfunc.h: Auto merged sql/item_subselect.cc: Auto merged sql/item_subselect.h: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/item_timefunc.cc: Auto merged sql/item_timefunc.h: Auto merged sql/item_uniq.cc: Auto merged sql/key.cc: Auto merged sql/lex.h: Auto merged sql/lex_symbol.h: Auto merged sql/lock.cc: Auto merged sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/log_event.h: Auto merged sql/my_decimal.cc: Auto merged sql/my_decimal.h: Auto merged sql/my_lock.c: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/net_serv.cc: Auto merged sql/opt_range.cc: Auto merged sql/opt_range.h: Auto merged sql/opt_sum.cc: Auto merged sql/parse_file.cc: Auto merged sql/parse_file.h: Auto merged sql/password.c: Auto merged sql/procedure.h: Auto merged sql/protocol.cc: Auto merged sql/protocol.h: Auto merged sql/records.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.cc: Auto merged sql/set_var.h: Auto merged sql/slave.cc: Auto merged sql/slave.h: Auto merged sql/sp.cc: Auto merged sql/sp.h: Auto merged sql/sp_cache.cc: Auto merged sql/sp_head.cc: Auto merged sql/sp_head.h: Auto merged sql/spatial.cc: Auto merged sql/spatial.h: Auto merged sql/sql_acl.cc: Auto merged sql/sql_acl.h: Auto merged sql/sql_analyse.cc: Auto merged sql/sql_analyse.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_bitmap.h: Auto merged sql/sql_cache.cc: Auto merged sql/sql_cache.h: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_crypt.cc: Auto merged sql/sql_cursor.cc: Auto merged sql/sql_db.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_derived.cc: Auto merged sql/sql_do.cc: Auto merged sql/sql_error.cc: Auto merged sql/sql_error.h: Auto merged sql/sql_handler.cc: Auto merged sql/sql_help.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_list.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_manager.cc: Auto merged sql/sql_map.cc: Auto merged sql/sql_olap.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_rename.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_repl.h: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_string.cc: Auto merged sql/sql_string.h: Auto merged sql/sql_table.cc: Auto merged sql/sql_test.cc: Auto merged sql/sql_trigger.cc: Auto merged sql/sql_trigger.h: Auto merged sql/sql_udf.cc: Auto merged sql/sql_union.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_view.cc: Auto merged sql-bench/Makefile.am: Auto merged sql-bench/as3ap.sh: Auto merged sql-bench/bench-count-distinct.sh: Auto merged sql-bench/bench-init.pl.sh: Auto merged sql-bench/compare-results.sh: Auto merged sql-bench/copy-db.sh: Auto merged sql/share/charsets/Index.xml: Auto merged sql/share/charsets/cp1250.xml: Auto merged sql/sql_view.h: Auto merged sql/sql_yacc.yy: Auto merged sql/stacktrace.c: Auto merged sql/stacktrace.h: Auto merged sql/strfunc.cc: Auto merged sql/structs.h: Auto merged sql/table.cc: Auto merged sql/table.h: Auto merged sql/time.cc: Auto merged sql/tztime.cc: Auto merged sql/tztime.h: Auto merged sql/udf_example.c: Auto merged sql/unireg.cc: Auto merged sql/unireg.h: Auto merged sql-bench/crash-me.sh: Auto merged sql-bench/run-all-tests.sh: Auto merged sql-bench/server-cfg.sh: Auto merged sql-bench/test-ATIS.sh: Auto merged sql-bench/test-alter-table.sh: Auto merged sql-bench/test-big-tables.sh: Auto merged sql-bench/test-connect.sh: Auto merged sql-bench/test-create.sh: Auto merged sql-bench/test-insert.sh: Auto merged sql-bench/test-select.sh: Auto merged sql-bench/test-transactions.sh: Auto merged sql-bench/test-wisconsin.sh: Auto merged sql-common/client.c: Auto merged sql-common/my_time.c: Auto merged storage/archive/ha_archive.cc: Auto merged storage/archive/ha_archive.h: Auto merged storage/blackhole/ha_blackhole.cc: Auto merged storage/blackhole/ha_blackhole.h: Auto merged storage/csv/ha_tina.cc: Auto merged storage/csv/ha_tina.h: Auto merged storage/example/ha_example.cc: Auto merged storage/example/ha_example.h: Auto merged storage/federated/ha_federated.cc: Auto merged storage/federated/ha_federated.h: Auto merged storage/heap/Makefile.am: Auto merged storage/heap/_check.c: Auto merged storage/heap/_rectest.c: Auto merged storage/heap/ha_heap.cc: Auto merged storage/heap/ha_heap.h: Auto merged storage/heap/heapdef.h: Auto merged storage/heap/hp_block.c: Auto merged storage/heap/hp_clear.c: Auto merged storage/heap/hp_close.c: Auto merged storage/heap/hp_create.c: Auto merged storage/heap/hp_delete.c: Auto merged storage/heap/hp_extra.c: Auto merged storage/heap/hp_hash.c: Auto merged storage/heap/hp_info.c: Auto merged storage/heap/hp_open.c: Auto merged storage/heap/hp_panic.c: Auto merged storage/heap/hp_rename.c: Auto merged storage/heap/hp_rfirst.c: Auto merged storage/heap/hp_rkey.c: Auto merged storage/heap/hp_rlast.c: Auto merged storage/heap/hp_rnext.c: Auto merged storage/heap/hp_rprev.c: Auto merged storage/heap/hp_rrnd.c: Auto merged storage/heap/hp_rsame.c: Auto merged storage/heap/hp_scan.c: Auto merged storage/heap/hp_static.c: Auto merged storage/heap/hp_test1.c: Auto merged storage/heap/hp_test2.c: Auto merged storage/heap/hp_update.c: Auto merged storage/heap/hp_write.c: Auto merged storage/innobase/Makefile.am: Auto merged storage/innobase/btr/Makefile.am: Auto merged storage/innobase/buf/Makefile.am: Auto merged storage/innobase/data/Makefile.am: Auto merged storage/innobase/dict/Makefile.am: Auto merged storage/innobase/dyn/Makefile.am: Auto merged storage/innobase/eval/Makefile.am: Auto merged storage/innobase/fil/Makefile.am: Auto merged storage/innobase/fsp/Makefile.am: Auto merged storage/innobase/fut/Makefile.am: Auto merged storage/innobase/ha/Makefile.am: Auto merged storage/innobase/handler/ha_innodb.cc: Auto merged storage/innobase/handler/ha_innodb.h: Auto merged storage/innobase/ibuf/Makefile.am: Auto merged storage/innobase/lock/Makefile.am: Auto merged storage/innobase/log/Makefile.am: Auto merged storage/innobase/mach/Makefile.am: Auto merged storage/innobase/mem/Makefile.am: Auto merged storage/innobase/mtr/Makefile.am: Auto merged storage/innobase/os/Makefile.am: Auto merged storage/innobase/page/Makefile.am: Auto merged storage/innobase/pars/Makefile.am: Auto merged storage/innobase/que/Makefile.am: Auto merged storage/innobase/read/Makefile.am: Auto merged storage/innobase/rem/Makefile.am: Auto merged storage/innobase/row/Makefile.am: Auto merged storage/innobase/srv/Makefile.am: Auto merged storage/innobase/sync/Makefile.am: Auto merged storage/innobase/thr/Makefile.am: Auto merged storage/innobase/trx/Makefile.am: Auto merged storage/innobase/usr/Makefile.am: Auto merged storage/innobase/ut/Makefile.am: Auto merged storage/myisam/Makefile.am: Auto merged storage/myisam/ft_boolean_search.c: Auto merged storage/myisam/ft_eval.c: Auto merged storage/myisam/ft_eval.h: Auto merged storage/myisam/ft_nlq_search.c: Auto merged storage/myisam/ft_parser.c: Auto merged storage/myisam/ft_static.c: Auto merged storage/myisam/ft_stem.c: Auto merged storage/myisam/ft_stopwords.c: Auto merged storage/myisam/ft_test1.c: Auto merged storage/myisam/ft_test1.h: Auto merged storage/myisam/ft_update.c: Auto merged storage/myisam/ftdefs.h: Auto merged storage/myisam/fulltext.h: Auto merged storage/myisam/ha_myisam.cc: Auto merged storage/myisam/ha_myisam.h: Auto merged storage/myisam/mi_cache.c: Auto merged storage/myisam/mi_changed.c: Auto merged storage/myisam/mi_check.c: Auto merged storage/myisam/mi_checksum.c: Auto merged storage/myisam/mi_close.c: Auto merged storage/myisam/mi_create.c: Auto merged storage/myisam/mi_dbug.c: Auto merged storage/myisam/mi_delete.c: Auto merged storage/myisam/mi_delete_all.c: Auto merged storage/myisam/mi_delete_table.c: Auto merged storage/myisam/mi_dynrec.c: Auto merged storage/myisam/mi_extra.c: Auto merged storage/myisam/mi_info.c: Auto merged storage/myisam/mi_key.c: Auto merged storage/myisam/mi_keycache.c: Auto merged storage/myisam/mi_locking.c: Auto merged storage/myisam/mi_log.c: Auto merged storage/myisam/mi_open.c: Auto merged storage/myisam/mi_packrec.c: Auto merged storage/myisam/mi_page.c: Auto merged storage/myisam/mi_panic.c: Auto merged storage/myisam/mi_preload.c: Auto merged storage/myisam/mi_range.c: Auto merged storage/myisam/mi_rename.c: Auto merged storage/myisam/mi_rfirst.c: Auto merged storage/myisam/mi_rkey.c: Auto merged storage/myisam/mi_rlast.c: Auto merged storage/myisam/mi_rnext.c: Auto merged storage/myisam/mi_rnext_same.c: Auto merged storage/myisam/mi_rprev.c: Auto merged storage/myisam/mi_rrnd.c: Auto merged storage/myisam/mi_rsame.c: Auto merged storage/myisam/mi_rsamepos.c: Auto merged storage/myisam/mi_scan.c: Auto merged storage/myisam/mi_search.c: Auto merged storage/myisam/mi_static.c: Auto merged storage/myisam/mi_statrec.c: Auto merged storage/myisam/mi_test1.c: Auto merged storage/myisam/mi_test2.c: Auto merged storage/myisam/mi_test3.c: Auto merged storage/myisam/mi_unique.c: Auto merged storage/myisam/mi_update.c: Auto merged storage/myisam/mi_write.c: Auto merged storage/myisam/myisam_ftdump.c: Auto merged storage/myisam/myisamchk.c: Auto merged storage/myisam/myisamdef.h: Auto merged storage/myisam/myisamlog.c: Auto merged storage/myisam/myisampack.c: Auto merged storage/myisam/rt_index.c: Auto merged storage/myisam/rt_index.h: Auto merged storage/myisam/rt_key.c: Auto merged storage/myisam/rt_key.h: Auto merged storage/myisam/rt_mbr.c: Auto merged storage/myisam/rt_mbr.h: Auto merged storage/myisam/rt_split.c: Auto merged storage/myisam/rt_test.c: Auto merged storage/myisam/sort.c: Auto merged storage/myisam/sp_defs.h: Auto merged storage/myisam/sp_key.c: Auto merged storage/myisam/sp_test.c: Auto merged storage/myisammrg/Makefile.am: Auto merged storage/myisammrg/ha_myisammrg.cc: Auto merged storage/myisammrg/ha_myisammrg.h: Auto merged storage/myisammrg/myrg_close.c: Auto merged storage/myisammrg/myrg_create.c: Auto merged storage/myisammrg/myrg_def.h: Auto merged storage/myisammrg/myrg_delete.c: Auto merged storage/myisammrg/myrg_extra.c: Auto merged storage/myisammrg/myrg_info.c: Auto merged storage/myisammrg/myrg_locking.c: Auto merged storage/myisammrg/myrg_open.c: Auto merged storage/myisammrg/myrg_panic.c: Auto merged storage/myisammrg/myrg_queue.c: Auto merged storage/myisammrg/myrg_range.c: Auto merged storage/myisammrg/myrg_rfirst.c: Auto merged storage/myisammrg/myrg_rkey.c: Auto merged storage/myisammrg/myrg_rlast.c: Auto merged storage/myisammrg/myrg_rnext.c: Auto merged storage/myisammrg/myrg_rnext_same.c: Auto merged storage/myisammrg/myrg_rprev.c: Auto merged storage/myisammrg/myrg_rrnd.c: Auto merged storage/myisammrg/myrg_rsame.c: Auto merged storage/myisammrg/myrg_static.c: Auto merged storage/myisammrg/myrg_update.c: Auto merged storage/myisammrg/myrg_write.c: Auto merged storage/ndb/include/debugger/DebuggerNames.hpp: Auto merged storage/ndb/include/debugger/EventLogger.hpp: Auto merged storage/ndb/include/debugger/GrepError.hpp: Auto merged storage/ndb/include/debugger/SignalLoggerManager.hpp: Auto merged storage/ndb/include/ndb_constants.h: Auto merged storage/ndb/include/ndb_global.h.in: Auto merged storage/ndb/include/ndb_init.h: Auto merged storage/ndb/include/ndb_types.h.in: Auto merged storage/ndb/include/ndb_version.h.in: Auto merged storage/ndb/include/editline/editline.h: Auto merged storage/ndb/include/kernel/AttributeDescriptor.hpp: Auto merged storage/ndb/include/kernel/AttributeHeader.hpp: Auto merged storage/ndb/include/kernel/AttributeList.hpp: Auto merged storage/ndb/include/kernel/BlockNumbers.h: Auto merged storage/ndb/include/kernel/GlobalSignalNumbers.h: Auto merged storage/ndb/include/kernel/GrepEvent.hpp: Auto merged storage/ndb/include/kernel/Interpreter.hpp: Auto merged storage/ndb/include/kernel/LogLevel.hpp: Auto merged storage/ndb/include/kernel/NodeBitmask.hpp: Auto merged storage/ndb/include/kernel/NodeInfo.hpp: Auto merged storage/ndb/include/kernel/NodeState.hpp: Auto merged storage/ndb/include/kernel/RefConvert.hpp: Auto merged storage/ndb/include/kernel/kernel_types.h: Auto merged storage/ndb/include/kernel/ndb_limits.h: Auto merged storage/ndb/include/kernel/signaldata/AbortAll.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccLock.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccScan.hpp: Auto merged storage/ndb/include/kernel/signaldata/AccSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterTable.hpp: Auto merged storage/ndb/include/kernel/signaldata/AlterTrig.hpp: Auto merged storage/ndb/include/kernel/signaldata/ApiBroadcast.hpp: Auto merged storage/ndb/include/kernel/signaldata/ApiRegSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/ApiVersion.hpp: Auto merged storage/ndb/include/kernel/signaldata/ArbitSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/AttrInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/BackupContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/BackupImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/BackupSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/BlockCommitOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/BuildIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/CheckNodeGroups.hpp: Auto merged storage/ndb/include/kernel/signaldata/CloseComReqConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/CmInit.hpp: Auto merged storage/ndb/include/kernel/trigger_definitions.h: Auto merged storage/ndb/include/kernel/signaldata/CmRegSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/CmvmiCfgConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/CntrMasterConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/CntrMasterReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/ConfigParamId.hpp: Auto merged storage/ndb/include/kernel/signaldata/ContinueFragmented.hpp: Auto merged storage/ndb/include/kernel/signaldata/CopyActive.hpp: Auto merged storage/ndb/include/kernel/signaldata/CopyFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/CopyGCIReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateEvnt.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateFragmentation.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateTable.hpp: Auto merged storage/ndb/include/kernel/signaldata/CreateTrig.hpp: Auto merged storage/ndb/include/kernel/signaldata/DiAddTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/DiGetNodes.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictLock.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictSchemaInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictStart.hpp: Auto merged storage/ndb/include/kernel/signaldata/DictTabInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihAddFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihStartTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/DihSwitchReplica.hpp: Auto merged storage/ndb/include/kernel/signaldata/DisconnectRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTabFile.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTable.hpp: Auto merged storage/ndb/include/kernel/signaldata/DropTrig.hpp: Auto merged storage/ndb/include/kernel/signaldata/DumpStateOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/EmptyLcp.hpp: Auto merged storage/ndb/include/kernel/signaldata/EndTo.hpp: Auto merged storage/ndb/include/kernel/signaldata/EventReport.hpp: Auto merged storage/ndb/include/kernel/signaldata/EventSubscribeReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/ExecFragReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FailRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/FireTrigOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsAppendReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsCloseReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsOpenReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsReadWriteReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsRef.hpp: Auto merged storage/ndb/include/kernel/signaldata/FsRemoveReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/GCPSave.hpp: Auto merged storage/ndb/include/kernel/signaldata/GetTabInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/GetTableId.hpp: Auto merged storage/ndb/include/kernel/signaldata/GrepImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/HotSpareRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/IndxAttrInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/IndxKeyInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/InvalidateNodeLCPConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/InvalidateNodeLCPReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/KeyInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/LCP.hpp: Auto merged storage/ndb/include/kernel/signaldata/ListTables.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhKey.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/LqhTransConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/ManagementServer.hpp: Auto merged storage/ndb/include/kernel/signaldata/MasterGCP.hpp: Auto merged storage/ndb/include/kernel/signaldata/MasterLCP.hpp: Auto merged storage/ndb/include/kernel/signaldata/NFCompleteRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/NdbSttor.hpp: Auto merged storage/ndb/include/kernel/signaldata/NdbfsContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/NextScan.hpp: Auto merged storage/ndb/include/kernel/signaldata/NodeFailRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/NodeStateSignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/PackedSignal.hpp: Auto merged storage/ndb/include/kernel/signaldata/PrepDropTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/PrepFailReqRef.hpp: Auto merged storage/ndb/include/kernel/signaldata/ReadNodesConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/RelTabMem.hpp: Auto merged storage/ndb/include/kernel/signaldata/RepImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/ResumeReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/ScanFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/ScanTab.hpp: Auto merged storage/ndb/include/kernel/signaldata/SetLogLevelOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/SetVarReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/SignalData.hpp: Auto merged storage/ndb/include/kernel/signaldata/SignalDataPrint.hpp: Auto merged storage/ndb/include/kernel/signaldata/SignalDroppedRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/SrFragidConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartFragReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartMe.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartPerm.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartRec.hpp: Auto merged storage/ndb/include/kernel/signaldata/StartTo.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopMe.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopPerm.hpp: Auto merged storage/ndb/include/kernel/signaldata/StopReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/SumaImpl.hpp: Auto merged storage/ndb/include/kernel/signaldata/SystemError.hpp: Auto merged storage/ndb/include/kernel/signaldata/TamperOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcCommit.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcHbRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcIndx.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyFailConf.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyRef.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcKeyReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcRollbackRep.hpp: Auto merged storage/ndb/include/kernel/signaldata/TcSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/TestOrd.hpp: Auto merged storage/ndb/include/kernel/signaldata/TransIdAI.hpp: Auto merged storage/ndb/include/kernel/signaldata/TrigAttrInfo.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupCommit.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupFrag.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupKey.hpp: Auto merged storage/ndb/include/kernel/signaldata/TupSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxBound.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxContinueB.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxMaint.hpp: Auto merged storage/ndb/include/kernel/signaldata/TuxSizeAltReq.hpp: Auto merged storage/ndb/include/kernel/signaldata/UpdateTo.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilDelete.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilExecute.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilLock.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilPrepare.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilRelease.hpp: Auto merged storage/ndb/include/kernel/signaldata/UtilSequence.hpp: Auto merged storage/ndb/include/kernel/signaldata/WaitGCP.hpp: Auto merged storage/ndb/include/logger/ConsoleLogHandler.hpp: Auto merged storage/ndb/include/logger/FileLogHandler.hpp: Auto merged storage/ndb/include/logger/LogHandler.hpp: Auto merged storage/ndb/include/logger/Logger.hpp: Auto merged storage/ndb/include/logger/SysLogHandler.hpp: Auto merged storage/ndb/include/mgmapi/mgmapi.h: Auto merged storage/ndb/include/mgmapi/mgmapi_debug.h: Auto merged storage/ndb/include/mgmapi/ndb_logevent.h: Auto merged storage/ndb/include/mgmapi/ndbd_exit_codes.h: Auto merged storage/ndb/include/mgmcommon/ConfigRetriever.hpp: Auto merged storage/ndb/include/mgmcommon/IPCConfig.hpp: Auto merged storage/ndb/include/mgmcommon/MgmtErrorReporter.hpp: Auto merged storage/ndb/include/ndbapi/Ndb.hpp: Auto merged storage/ndb/include/ndbapi/NdbApi.hpp: Auto merged storage/ndb/include/ndbapi/NdbBlob.hpp: Auto merged storage/ndb/include/ndbapi/NdbDictionary.hpp: Auto merged storage/ndb/include/ndbapi/NdbError.hpp: Auto merged storage/ndb/include/ndbapi/NdbEventOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbPool.hpp: Auto merged storage/ndb/include/ndbapi/NdbRecAttr.hpp: Auto merged storage/ndb/include/ndbapi/NdbReceiver.hpp: Auto merged storage/ndb/include/ndbapi/NdbScanFilter.hpp: Auto merged storage/ndb/include/ndbapi/NdbScanOperation.hpp: Auto merged storage/ndb/include/ndbapi/NdbTransaction.hpp: Auto merged storage/ndb/include/ndbapi/ndb_cluster_connection.hpp: Auto merged storage/ndb/include/ndbapi/ndb_opt_defaults.h: Auto merged storage/ndb/include/ndbapi/ndbapi_limits.h: Auto merged storage/ndb/include/ndbapi/ndberror.h: Auto merged storage/ndb/include/newtonapi/dba.h: Auto merged storage/ndb/include/newtonapi/defs/pcn_types.h: Auto merged storage/ndb/include/portlib/NdbCondition.h: Auto merged storage/ndb/include/portlib/NdbConfig.h: Auto merged storage/ndb/include/portlib/NdbDaemon.h: Auto merged storage/ndb/include/portlib/NdbEnv.h: Auto merged storage/ndb/include/portlib/NdbHost.h: Auto merged storage/ndb/include/portlib/NdbMain.h: Auto merged storage/ndb/include/portlib/NdbMem.h: Auto merged storage/ndb/include/portlib/NdbMutex.h: Auto merged storage/ndb/include/portlib/NdbSleep.h: Auto merged storage/ndb/include/portlib/NdbTCP.h: Auto merged storage/ndb/include/portlib/NdbThread.h: Auto merged storage/ndb/include/portlib/NdbTick.h: Auto merged storage/ndb/include/portlib/PortDefs.h: Auto merged storage/ndb/include/portlib/prefetch.h: Auto merged storage/ndb/include/transporter/TransporterCallback.hpp: Auto merged storage/ndb/include/transporter/TransporterDefinitions.hpp: Auto merged storage/ndb/include/transporter/TransporterRegistry.hpp: Auto merged storage/ndb/include/util/BaseString.hpp: Auto merged storage/ndb/include/util/Bitmask.hpp: Auto merged storage/ndb/include/util/File.hpp: Auto merged storage/ndb/include/util/InputStream.hpp: Auto merged storage/ndb/include/util/NdbAutoPtr.hpp: Auto merged storage/ndb/include/util/NdbOut.hpp: Auto merged storage/ndb/include/util/NdbSqlUtil.hpp: Auto merged storage/ndb/include/util/OutputStream.hpp: Auto merged storage/ndb/include/util/Parser.hpp: Auto merged storage/ndb/include/util/Properties.hpp: Auto merged storage/ndb/include/util/SimpleProperties.hpp: Auto merged storage/ndb/include/util/SocketAuthenticator.hpp: Auto merged storage/ndb/include/util/SocketClient.hpp: Auto merged storage/ndb/include/util/SocketServer.hpp: Auto merged storage/ndb/include/util/UtilBuffer.hpp: Auto merged storage/ndb/include/util/Vector.hpp: Auto merged storage/ndb/include/util/basestring_vsnprintf.h: Auto merged storage/ndb/include/util/md5_hash.hpp: Auto merged storage/ndb/include/util/ndb_opts.h: Auto merged storage/ndb/include/util/random.h: Auto merged storage/ndb/include/util/socket_io.h: Auto merged storage/ndb/include/util/uucode.h: Auto merged storage/ndb/include/util/version.h: Auto merged storage/ndb/src/common/debugger/BlockNames.cpp: Auto merged storage/ndb/src/common/debugger/DebuggerNames.cpp: Auto merged storage/ndb/src/common/debugger/EventLogger.cpp: Auto merged storage/ndb/src/common/debugger/GrepError.cpp: Auto merged storage/ndb/src/common/debugger/SignalLoggerManager.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AccLock.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterTable.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/AlterTrig.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/BackupImpl.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/BackupSignalData.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CloseComReqConf.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/ContinueB.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CopyGCI.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateEvnt.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateFragmentation.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/CreateTrig.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DictTabInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DihContinueB.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DihSwitchReplicaReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DisconnectRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DropIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DropTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/DropTrig.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FailRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FireTrigOrd.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsAppendReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsCloseReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsConf.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsOpenReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsReadWriteReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/FsRef.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/GCPSave.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/IndxAttrInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/IndxKeyInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LCP.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LqhFrag.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LqhKey.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/LqhTrans.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/MasterLCP.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/NFCompleteRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/NdbSttor.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/NdbfsContinueB.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/PackedSignal.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/PrepDropTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/PrepFailReqRef.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/ScanFrag.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/ScanTab.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SignalDroppedRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SignalNames.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/StartRec.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SumaImpl.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/SystemError.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcIndx.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcKeyConf.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcKeyRef.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcKeyReq.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TcRollbackRep.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TrigAttrInfo.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TupCommit.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TupKey.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/TuxMaint.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilDelete.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilExecute.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilLock.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilPrepare.cpp: Auto merged storage/ndb/src/common/debugger/signaldata/UtilSequence.cpp: Auto merged storage/ndb/src/common/logger/ConsoleLogHandler.cpp: Auto merged storage/ndb/src/common/logger/FileLogHandler.cpp: Auto merged storage/ndb/src/common/logger/LogHandler.cpp: Auto merged storage/ndb/src/common/logger/LogHandlerList.cpp: Auto merged storage/ndb/src/common/logger/LogHandlerList.hpp: Auto merged storage/ndb/src/common/logger/Logger.cpp: Auto merged storage/ndb/src/common/logger/SysLogHandler.cpp: Auto merged storage/ndb/src/common/logger/listtest/LogHandlerListUnitTest.cpp: Auto merged storage/ndb/src/common/logger/listtest/LogHandlerListUnitTest.hpp: Auto merged storage/ndb/src/common/logger/loggertest/LoggerUnitTest.cpp: Auto merged storage/ndb/src/common/logger/loggertest/LoggerUnitTest.hpp: Auto merged storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp: Auto merged storage/ndb/src/common/mgmcommon/IPCConfig.cpp: Auto merged storage/ndb/src/common/mgmcommon/printConfig/printConfig.cpp: Auto merged storage/ndb/src/common/portlib/NdbCondition.c: Auto merged storage/ndb/src/common/portlib/NdbConfig.c: Auto merged storage/ndb/src/common/portlib/NdbDaemon.c: Auto merged storage/ndb/src/common/portlib/NdbEnv.c: Auto merged storage/ndb/src/common/portlib/NdbHost.c: Auto merged storage/ndb/src/common/portlib/NdbMem.c: Auto merged storage/ndb/src/common/portlib/NdbMutex.c: Auto merged storage/ndb/src/common/portlib/NdbPortLibTest.cpp: Auto merged storage/ndb/src/common/portlib/NdbSleep.c: Auto merged storage/ndb/src/common/portlib/NdbTCP.cpp: Auto merged storage/ndb/src/common/portlib/NdbThread.c: Auto merged storage/ndb/src/common/portlib/NdbTick.c: Auto merged storage/ndb/src/common/portlib/memtest.c: Auto merged storage/ndb/src/common/portlib/mmstest.cpp: Auto merged storage/ndb/src/common/portlib/munmaptest.cpp: Auto merged storage/ndb/src/common/portlib/win32/NdbCondition.c: Auto merged storage/ndb/src/common/portlib/win32/NdbDaemon.c: Auto merged storage/ndb/src/common/portlib/win32/NdbEnv.c: Auto merged storage/ndb/src/common/portlib/win32/NdbHost.c: Auto merged storage/ndb/src/common/portlib/win32/NdbMem.c: Auto merged storage/ndb/src/common/portlib/win32/NdbMutex.c: Auto merged storage/ndb/src/common/portlib/win32/NdbSleep.c: Auto merged storage/ndb/src/common/portlib/win32/NdbTCP.c: Auto merged storage/ndb/src/common/portlib/win32/NdbThread.c: Auto merged storage/ndb/src/common/portlib/win32/NdbTick.c: Auto merged storage/ndb/src/common/transporter/Packer.cpp: Auto merged storage/ndb/src/common/transporter/Packer.hpp: Auto merged storage/ndb/src/common/transporter/SCI_Transporter.cpp: Auto merged storage/ndb/src/common/transporter/SCI_Transporter.hpp: Auto merged storage/ndb/src/common/transporter/SHM_Buffer.hpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.cpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.hpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.unix.cpp: Auto merged storage/ndb/src/common/transporter/SHM_Transporter.win32.cpp: Auto merged storage/ndb/src/common/transporter/SendBuffer.cpp: Auto merged storage/ndb/src/common/transporter/SendBuffer.hpp: Auto merged storage/ndb/src/common/transporter/TCP_Transporter.cpp: Auto merged storage/ndb/src/common/transporter/TCP_Transporter.hpp: Auto merged storage/ndb/src/common/transporter/Transporter.cpp: Auto merged storage/ndb/src/common/transporter/Transporter.hpp: Auto merged storage/ndb/src/common/transporter/TransporterInternalDefinitions.hpp: Auto merged storage/ndb/src/common/transporter/TransporterRegistry.cpp: Auto merged storage/ndb/src/common/transporter/basictest/basicTransporterTest.cpp: Auto merged storage/ndb/src/common/transporter/buddy.cpp: Auto merged storage/ndb/src/common/transporter/buddy.hpp: Auto merged storage/ndb/src/common/transporter/failoverSCI/failoverSCI.cpp: Auto merged storage/ndb/src/common/transporter/perftest/perfTransporterTest.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioSCI/prioSCI.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioSHM/prioSHM.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioTCP/prioTCP.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioTransporterTest.cpp: Auto merged storage/ndb/src/common/transporter/priotest/prioTransporterTest.hpp: Auto merged storage/ndb/src/common/util/BaseString.cpp: Auto merged storage/ndb/src/common/util/File.cpp: Auto merged storage/ndb/src/common/util/InputStream.cpp: Auto merged storage/ndb/src/common/util/NdbOut.cpp: Auto merged storage/ndb/src/common/util/NdbSqlUtil.cpp: Auto merged storage/ndb/src/common/util/OutputStream.cpp: Auto merged storage/ndb/src/common/util/Parser.cpp: Auto merged storage/ndb/src/common/util/Properties.cpp: Auto merged storage/ndb/src/common/util/SimpleProperties.cpp: Auto merged storage/ndb/src/common/util/SocketAuthenticator.cpp: Auto merged storage/ndb/src/common/util/SocketClient.cpp: Auto merged storage/ndb/src/common/util/SocketServer.cpp: Auto merged storage/ndb/src/common/util/basestring_vsnprintf.c: Auto merged storage/ndb/src/common/util/md5_hash.cpp: Auto merged storage/ndb/src/common/util/ndb_init.c: Auto merged storage/ndb/src/common/util/random.c: Auto merged storage/ndb/src/common/util/socket_io.cpp: Auto merged storage/ndb/src/common/util/strdup.c: Auto merged storage/ndb/src/common/util/filetest/FileUnitTest.cpp: Auto merged storage/ndb/src/common/util/filetest/FileUnitTest.hpp: Auto merged storage/ndb/src/common/util/testProperties/testProperties.cpp: Auto merged storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp: Auto merged storage/ndb/src/common/util/uucode.c: Auto merged storage/ndb/src/common/util/version.c: Auto merged storage/ndb/src/cw/cpcc-win32/C++/CPC_GUI.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/CPC_GUI.h: Auto merged storage/ndb/src/cw/cpcc-win32/C++/NdbControls.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/StdAfx.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/StdAfx.h: Auto merged storage/ndb/src/cw/cpcc-win32/C++/TreeView.cpp: Auto merged storage/ndb/src/cw/cpcc-win32/C++/TreeView.h: Auto merged storage/ndb/src/cw/cpcc-win32/C++/resource.h: Auto merged storage/ndb/src/cw/cpcd/APIService.cpp: Auto merged storage/ndb/src/cw/cpcd/APIService.hpp: Auto merged storage/ndb/src/cw/cpcd/CPCD.cpp: Auto merged storage/ndb/src/cw/cpcd/CPCD.hpp: Auto merged storage/ndb/src/cw/cpcd/Monitor.cpp: Auto merged storage/ndb/src/cw/cpcd/Process.cpp: Auto merged storage/ndb/src/cw/cpcd/common.cpp: Auto merged storage/ndb/src/cw/cpcd/common.hpp: Auto merged storage/ndb/src/cw/cpcd/main.cpp: Auto merged storage/ndb/src/cw/test/socketclient/socketClientTest.cpp: Auto merged storage/ndb/src/cw/util/ClientInterface.cpp: Auto merged storage/ndb/src/cw/util/ClientInterface.hpp: Auto merged storage/ndb/src/cw/util/SocketRegistry.cpp: Auto merged storage/ndb/src/cw/util/SocketRegistry.hpp: Auto merged storage/ndb/src/cw/util/SocketService.cpp: Auto merged storage/ndb/src/cw/util/SocketService.hpp: Auto merged storage/ndb/src/kernel/SimBlockList.cpp: Auto merged storage/ndb/src/kernel/blocks/mutexes.hpp: Auto merged storage/ndb/src/kernel/main.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/Backup.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/Backup.hpp: Auto merged storage/ndb/src/kernel/blocks/backup/BackupFormat.hpp: Auto merged storage/ndb/src/kernel/blocks/backup/BackupInit.cpp: Auto merged storage/ndb/src/kernel/blocks/backup/FsBuffer.hpp: Auto merged storage/ndb/src/kernel/blocks/backup/read.cpp: Auto merged storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp: Auto merged storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.hpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/Dbacc.hpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/DbaccInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/SchemaFile.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/Dbdih.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/DbdihInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/Sysfile.hpp: Auto merged storage/ndb/src/kernel/blocks/dbdih/printSysfile/printSysfile.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/DblqhInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp: Auto merged storage/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/DbtcInit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/AttributeOffset.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupAbort.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupBuffer.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupCommit.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupDebug.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupFixAlloc.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupIndex.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupPageMap.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupStoredProcDef.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupTabDesMan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxCmp.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxMaint.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxNode.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxSearch.cpp: Auto merged storage/ndb/src/kernel/blocks/dbtux/DbtuxTree.cpp: Auto merged storage/ndb/src/kernel/blocks/dbutil/DbUtil.cpp: Auto merged storage/ndb/src/kernel/blocks/dbutil/DbUtil.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/Ndbcntr.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrInit.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbcntr/NdbcntrSysTable.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/AsyncFile.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/AsyncFileTest/AsyncFileTest.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/CircularIndex.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/CircularIndex.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Filename.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Filename.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/MemoryChannel.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/MemoryChannelTest/MemoryChannelTest.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.cpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Ndbfs.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/OpenFiles.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/Pool.hpp: Auto merged storage/ndb/src/kernel/blocks/ndbfs/VoidFs.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/Qmgr.hpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrInit.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp: Auto merged storage/ndb/src/kernel/blocks/qmgr/timer.hpp: Auto merged storage/ndb/src/kernel/blocks/suma/Suma.cpp: Auto merged storage/ndb/src/kernel/blocks/suma/Suma.hpp: Auto merged storage/ndb/src/kernel/blocks/suma/SumaInit.cpp: Auto merged storage/ndb/src/kernel/blocks/trix/Trix.cpp: Auto merged storage/ndb/src/kernel/blocks/trix/Trix.hpp: Auto merged storage/ndb/src/kernel/error/ErrorHandlingMacros.hpp: Auto merged storage/ndb/src/kernel/error/ErrorReporter.cpp: Auto merged storage/ndb/src/kernel/error/ErrorReporter.hpp: Auto merged storage/ndb/src/kernel/error/TimeModule.cpp: Auto merged storage/ndb/src/kernel/error/TimeModule.hpp: Auto merged storage/ndb/src/kernel/error/ndbd_exit_codes.c: Auto merged storage/ndb/src/kernel/vm/Array.hpp: Auto merged storage/ndb/src/kernel/vm/ArrayPool.hpp: Auto merged storage/ndb/src/kernel/vm/CArray.hpp: Auto merged storage/ndb/src/kernel/vm/Callback.hpp: Auto merged storage/ndb/src/kernel/vm/ClusterConfiguration.cpp: Auto merged storage/ndb/src/kernel/vm/ClusterConfiguration.hpp: Auto merged storage/ndb/src/kernel/vm/Configuration.cpp: Auto merged storage/ndb/src/kernel/vm/Configuration.hpp: Auto merged storage/ndb/src/kernel/vm/DLFifoList.hpp: Auto merged storage/ndb/src/kernel/vm/DLHashTable.hpp: Auto merged storage/ndb/src/kernel/vm/DLHashTable2.hpp: Auto merged storage/ndb/src/kernel/vm/DLList.hpp: Auto merged storage/ndb/src/kernel/vm/DataBuffer.hpp: Auto merged storage/ndb/src/kernel/vm/Emulator.cpp: Auto merged storage/ndb/src/kernel/vm/Emulator.hpp: Auto merged storage/ndb/src/kernel/vm/FastScheduler.cpp: Auto merged storage/ndb/src/kernel/vm/FastScheduler.hpp: Auto merged storage/ndb/src/kernel/vm/GlobalData.hpp: Auto merged storage/ndb/src/kernel/vm/KeyDescriptor.hpp: Auto merged storage/ndb/src/kernel/vm/KeyTable.hpp: Auto merged storage/ndb/src/kernel/vm/KeyTable2.hpp: Auto merged storage/ndb/src/kernel/vm/LongSignal.hpp: Auto merged storage/ndb/src/kernel/vm/Mutex.cpp: Auto merged storage/ndb/src/kernel/vm/Mutex.hpp: Auto merged storage/ndb/src/kernel/vm/Prio.hpp: Auto merged storage/ndb/src/kernel/vm/RequestTracker.hpp: Auto merged storage/ndb/src/kernel/vm/SLList.hpp: Auto merged storage/ndb/src/kernel/vm/SafeCounter.cpp: Auto merged storage/ndb/src/kernel/vm/SafeCounter.hpp: Auto merged storage/ndb/src/kernel/vm/SectionReader.cpp: Auto merged storage/ndb/src/kernel/vm/SectionReader.hpp: Auto merged storage/ndb/src/kernel/vm/SignalCounter.hpp: Auto merged storage/ndb/src/kernel/vm/SimBlockList.hpp: Auto merged storage/ndb/src/kernel/vm/SimplePropertiesSection.cpp: Auto merged storage/ndb/src/kernel/vm/SimulatedBlock.cpp: Auto merged storage/ndb/src/kernel/vm/SimulatedBlock.hpp: Auto merged storage/ndb/src/kernel/vm/SuperPool.cpp: Auto merged storage/ndb/src/kernel/vm/SuperPool.hpp: Auto merged storage/ndb/src/kernel/vm/ThreadConfig.cpp: Auto merged storage/ndb/src/kernel/vm/ThreadConfig.hpp: Auto merged storage/ndb/src/kernel/vm/TimeQueue.cpp: Auto merged storage/ndb/src/kernel/vm/TimeQueue.hpp: Auto merged storage/ndb/src/kernel/vm/TransporterCallback.cpp: Auto merged storage/ndb/src/kernel/vm/VMSignal.cpp: Auto merged storage/ndb/src/kernel/vm/VMSignal.hpp: Auto merged storage/ndb/src/kernel/vm/WaitQueue.hpp: Auto merged storage/ndb/src/kernel/vm/WatchDog.cpp: Auto merged storage/ndb/src/kernel/vm/WatchDog.hpp: Auto merged storage/ndb/src/kernel/vm/al_test/arrayListTest.cpp: Auto merged storage/ndb/src/kernel/vm/al_test/arrayPoolTest.cpp: Auto merged storage/ndb/src/kernel/vm/al_test/main.cpp: Auto merged storage/ndb/src/kernel/vm/ndbd_malloc.cpp: Auto merged storage/ndb/src/kernel/vm/ndbd_malloc.hpp: Auto merged storage/ndb/src/kernel/vm/pc.hpp: Auto merged storage/ndb/src/kernel/vm/testCopy/rr.cpp: Auto merged storage/ndb/src/kernel/vm/testCopy/testCopy.cpp: Auto merged storage/ndb/src/kernel/vm/testDataBuffer/testDataBuffer.cpp: Auto merged storage/ndb/src/kernel/vm/testLongSig/testLongSig.cpp: Auto merged storage/ndb/src/kernel/vm/testSimplePropertiesSection/test.cpp: Auto merged storage/ndb/src/kernel/vm/testSuperPool.cpp: Auto merged storage/ndb/src/mgmapi/LocalConfig.cpp: Auto merged storage/ndb/src/mgmapi/LocalConfig.hpp: Auto merged storage/ndb/src/mgmapi/mgmapi.cpp: Auto merged storage/ndb/src/mgmapi/mgmapi_configuration.hpp: Auto merged storage/ndb/src/mgmapi/mgmapi_internal.h: Auto merged storage/ndb/src/mgmapi/ndb_logevent.cpp: Auto merged storage/ndb/src/mgmapi/ndb_logevent.hpp: Auto merged storage/ndb/src/mgmapi/test/keso.c: Auto merged storage/ndb/src/mgmapi/test/mgmSrvApi.cpp: Auto merged storage/ndb/src/mgmclient/CommandInterpreter.cpp: Auto merged storage/ndb/src/mgmclient/main.cpp: Auto merged storage/ndb/src/mgmclient/ndb_mgmclient.hpp: Auto merged storage/ndb/src/mgmclient/ndb_mgmclient.h: Auto merged storage/ndb/src/mgmclient/test_cpcd/test_cpcd.cpp: Auto merged storage/ndb/src/mgmsrv/Config.cpp: Auto merged storage/ndb/src/mgmsrv/Config.hpp: Auto merged storage/ndb/src/mgmsrv/ConfigInfo.cpp: Auto merged storage/ndb/src/mgmsrv/ConfigInfo.hpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.cpp: Auto merged storage/ndb/src/mgmsrv/InitConfigFileParser.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvr.cpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvr.hpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp: Auto merged storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp: Auto merged storage/ndb/src/mgmsrv/Services.cpp: Auto merged storage/ndb/src/mgmsrv/Services.hpp: Auto merged storage/ndb/src/mgmsrv/SignalQueue.cpp: Auto merged storage/ndb/src/mgmsrv/SignalQueue.hpp: Auto merged storage/ndb/src/mgmsrv/convertStrToInt.cpp: Auto merged storage/ndb/src/mgmsrv/convertStrToInt.hpp: Auto merged storage/ndb/src/mgmsrv/main.cpp: Auto merged storage/ndb/src/mgmsrv/mkconfig/mkconfig.cpp: Auto merged storage/ndb/src/ndbapi/API.hpp: Auto merged storage/ndb/src/ndbapi/ClusterMgr.cpp: Auto merged storage/ndb/src/ndbapi/ClusterMgr.hpp: Auto merged storage/ndb/src/ndbapi/DictCache.cpp: Auto merged storage/ndb/src/ndbapi/DictCache.hpp: Auto merged storage/ndb/src/ndbapi/Ndb.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.cpp: Auto merged storage/ndb/src/ndbapi/NdbApiSignal.hpp: Auto merged storage/ndb/src/ndbapi/NdbBlob.cpp: Auto merged storage/ndb/src/ndbapi/NdbBlobImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbDictionary.cpp: Auto merged storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp: Auto merged storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbErrorOut.cpp: Auto merged storage/ndb/src/ndbapi/NdbEventOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp: Auto merged storage/ndb/src/ndbapi/NdbEventOperationImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbIndexOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbLinHash.hpp: Auto merged storage/ndb/src/ndbapi/NdbOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationDefine.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationExec.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationInt.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationScan.cpp: Auto merged storage/ndb/src/ndbapi/NdbOperationSearch.cpp: Auto merged storage/ndb/src/ndbapi/NdbPool.cpp: Auto merged storage/ndb/src/ndbapi/NdbPoolImpl.cpp: Auto merged storage/ndb/src/ndbapi/NdbPoolImpl.hpp: Auto merged storage/ndb/src/ndbapi/NdbRecAttr.cpp: Auto merged storage/ndb/src/ndbapi/NdbReceiver.cpp: Auto merged storage/ndb/src/ndbapi/NdbScanFilter.cpp: Auto merged storage/ndb/src/ndbapi/NdbScanOperation.cpp: Auto merged storage/ndb/src/ndbapi/NdbTransaction.cpp: Auto merged storage/ndb/src/ndbapi/NdbTransactionScan.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.cpp: Auto merged storage/ndb/src/ndbapi/NdbUtil.hpp: Auto merged storage/ndb/src/ndbapi/NdbWaiter.hpp: Auto merged storage/ndb/src/ndbapi/Ndberr.cpp: Auto merged storage/ndb/src/ndbapi/Ndbif.cpp: Auto merged storage/ndb/src/ndbapi/Ndbinit.cpp: Auto merged storage/ndb/src/ndbapi/Ndblist.cpp: Auto merged storage/ndb/src/ndbapi/ObjectMap.hpp: Auto merged storage/ndb/src/ndbapi/SignalSender.cpp: Auto merged storage/ndb/src/ndbapi/SignalSender.hpp: Auto merged storage/ndb/src/ndbapi/TransporterFacade.cpp: Auto merged storage/ndb/src/ndbapi/TransporterFacade.hpp: Auto merged storage/ndb/src/ndbapi/ndb_cluster_connection.cpp: Auto merged storage/ndb/src/ndbapi/ndb_cluster_connection_impl.hpp: Auto merged storage/ndb/src/ndbapi/ndberror.c: Auto merged storage/ndb/src/ndbapi/signal-sender/SignalSender.cpp: Auto merged storage/ndb/src/ndbapi/signal-sender/SignalSender.hpp: Auto merged storage/ndb/test/include/CpcClient.hpp: Auto merged storage/ndb/test/include/HugoAsynchTransactions.hpp: Auto merged storage/ndb/test/include/HugoCalculator.hpp: Auto merged storage/ndb/test/include/HugoOperations.hpp: Auto merged storage/ndb/test/include/HugoTransactions.hpp: Auto merged storage/ndb/test/include/NDBT.hpp: Auto merged storage/ndb/test/include/NDBT_DataSet.hpp: Auto merged storage/ndb/test/include/NDBT_DataSetTransaction.hpp: Auto merged storage/ndb/test/include/NDBT_Error.hpp: Auto merged storage/ndb/test/include/NDBT_Output.hpp: Auto merged storage/ndb/test/include/NDBT_ResultRow.hpp: Auto merged storage/ndb/test/include/NDBT_ReturnCodes.h: Auto merged storage/ndb/test/include/NDBT_Stats.hpp: Auto merged storage/ndb/test/include/NDBT_Table.hpp: Auto merged storage/ndb/test/include/NDBT_Tables.hpp: Auto merged storage/ndb/test/include/NDBT_Test.hpp: Auto merged storage/ndb/test/include/NdbBackup.hpp: Auto merged storage/ndb/test/include/NdbConfig.hpp: Auto merged storage/ndb/test/include/NdbGrep.hpp: Auto merged storage/ndb/test/include/NdbRestarter.hpp: Auto merged storage/ndb/test/include/NdbRestarts.hpp: Auto merged storage/ndb/test/include/NdbSchemaCon.hpp: Auto merged storage/ndb/test/include/NdbSchemaOp.hpp: Auto merged storage/ndb/test/include/NdbTest.hpp: Auto merged storage/ndb/test/include/NdbTimer.hpp: Auto merged storage/ndb/test/include/TestNdbEventOperation.hpp: Auto merged storage/ndb/test/include/UtilTransactions.hpp: Auto merged storage/ndb/test/include/getarg.h: Auto merged storage/ndb/test/ndbapi/InsertRecs.cpp: Auto merged storage/ndb/test/ndbapi/ScanFilter.hpp: Auto merged storage/ndb/test/ndbapi/ScanFunctions.hpp: Auto merged storage/ndb/test/ndbapi/ScanInterpretTest.hpp: Auto merged storage/ndb/test/ndbapi/TraceNdbApi.cpp: Auto merged storage/ndb/test/ndbapi/VerifyNdbApi.cpp: Auto merged storage/ndb/test/ndbapi/acid.cpp: Auto merged storage/ndb/test/ndbapi/acid2.cpp: Auto merged storage/ndb/test/ndbapi/adoInsertRecs.cpp: Auto merged storage/ndb/test/ndbapi/asyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/benchronja.cpp: Auto merged storage/ndb/test/ndbapi/bulk_copy.cpp: Auto merged storage/ndb/test/ndbapi/cdrserver.cpp: Auto merged storage/ndb/test/ndbapi/celloDb.cpp: Auto merged storage/ndb/test/ndbapi/create_all_tabs.cpp: Auto merged storage/ndb/test/ndbapi/create_tab.cpp: Auto merged storage/ndb/test/ndbapi/drop_all_tabs.cpp: Auto merged storage/ndb/test/ndbapi/flexAsynch.cpp: Auto merged storage/ndb/test/ndbapi/flexBench.cpp: Auto merged storage/ndb/test/ndbapi/flexHammer.cpp: Auto merged storage/ndb/test/ndbapi/flexScan.cpp: Auto merged storage/ndb/test/ndbapi/flexTT.cpp: Auto merged storage/ndb/test/ndbapi/flexTimedAsynch.cpp: Auto merged storage/ndb/test/ndbapi/flex_bench_mysql.cpp: Auto merged storage/ndb/test/ndbapi/index.cpp: Auto merged storage/ndb/test/ndbapi/index2.cpp: Auto merged storage/ndb/test/ndbapi/initronja.cpp: Auto merged storage/ndb/test/ndbapi/interpreterInTup.cpp: Auto merged storage/ndb/test/ndbapi/mainAsyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/msa.cpp: Auto merged storage/ndb/test/ndbapi/ndb_async1.cpp: Auto merged storage/ndb/test/ndbapi/ndb_async2.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_populate.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction2.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction3.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction4.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction5.cpp: Auto merged storage/ndb/test/ndbapi/ndb_user_transaction6.cpp: Auto merged storage/ndb/test/ndbapi/restarter.cpp: Auto merged storage/ndb/test/ndbapi/restarter2.cpp: Auto merged storage/ndb/test/ndbapi/restarts.cpp: Auto merged storage/ndb/test/ndbapi/size.cpp: Auto merged storage/ndb/test/ndbapi/testBackup.cpp: Auto merged storage/ndb/test/ndbapi/testBasic.cpp: Auto merged storage/ndb/test/ndbapi/testBasicAsynch.cpp: Auto merged storage/ndb/test/ndbapi/testBlobs.cpp: Auto merged storage/ndb/test/ndbapi/testDataBuffers.cpp: Auto merged storage/ndb/test/ndbapi/testDeadlock.cpp: Auto merged storage/ndb/test/ndbapi/testDict.cpp: Auto merged storage/ndb/test/ndbapi/testGrepVerify.cpp: Auto merged storage/ndb/test/ndbapi/testIndex.cpp: Auto merged storage/ndb/test/ndbapi/testInterpreter.cpp: Auto merged storage/ndb/test/ndbapi/testMgm.cpp: Auto merged storage/ndb/test/ndbapi/testNdbApi.cpp: Auto merged storage/ndb/test/ndbapi/testNodeRestart.cpp: Auto merged storage/ndb/test/ndbapi/testOIBasic.cpp: Auto merged storage/ndb/test/ndbapi/testOperations.cpp: Auto merged storage/ndb/test/ndbapi/testOrderedIndex.cpp: Auto merged storage/ndb/test/ndbapi/testPartitioning.cpp: Auto merged storage/ndb/test/ndbapi/testReadPerf.cpp: Auto merged storage/ndb/test/ndbapi/bank/Bank.cpp: Auto merged storage/ndb/test/ndbapi/bank/Bank.hpp: Auto merged storage/ndb/test/ndbapi/bank/BankLoad.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankCreator.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankMakeGL.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankSumAccounts.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankTimer.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankTransactionMaker.cpp: Auto merged storage/ndb/test/ndbapi/bank/bankValidateAllGLs.cpp: Auto merged storage/ndb/test/ndbapi/bank/testBank.cpp: Auto merged storage/ndb/test/ndbapi/bench/asyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/bench/dbGenerator.h: Auto merged storage/ndb/test/ndbapi/bench/dbPopulate.cpp: Auto merged storage/ndb/test/ndbapi/bench/dbPopulate.h: Auto merged storage/ndb/test/ndbapi/bench/macros.h: Auto merged storage/ndb/test/ndbapi/bench/mainAsyncGenerator.cpp: Auto merged storage/ndb/test/ndbapi/bench/mainPopulate.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_async1.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_async2.cpp: Auto merged storage/ndb/test/ndbapi/testRestartGci.cpp: Auto merged storage/ndb/test/ndbapi/testSRBank.cpp: Auto merged storage/ndb/test/ndbapi/testScan.cpp: Auto merged storage/ndb/test/ndbapi/testScanInterpreter.cpp: Auto merged storage/ndb/test/ndbapi/testScanPerf.cpp: Auto merged storage/ndb/test/ndbapi/testSystemRestart.cpp: Auto merged storage/ndb/test/ndbapi/testTimeout.cpp: Auto merged storage/ndb/test/ndbapi/testTransactions.cpp: Auto merged storage/ndb/test/ndbapi/test_event.cpp: Auto merged storage/ndb/test/ndbapi/test_event_merge.cpp: Auto merged storage/ndb/test/ndbapi/test_event_multi_table.cpp: Auto merged storage/ndb/test/ndbapi/userInterface.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_error.hpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_schema.hpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction2.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction3.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction4.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction5.cpp: Auto merged storage/ndb/test/ndbapi/bench/ndb_user_transaction6.cpp: Auto merged storage/ndb/test/ndbapi/bench/testData.h: Auto merged storage/ndb/test/ndbapi/bench/testDefinitions.h: Auto merged storage/ndb/test/ndbapi/bench/userInterface.cpp: Auto merged storage/ndb/test/ndbapi/bench/userInterface.h: Auto merged storage/ndb/test/newtonapi/basic_test/basic/basic.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/bulk_read/br_test.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/common.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/common.hpp: Auto merged storage/ndb/test/newtonapi/basic_test/ptr_binding/ptr_binding_test.cpp: Auto merged storage/ndb/test/newtonapi/basic_test/too_basic.cpp: Auto merged storage/ndb/test/newtonapi/perf_test/perf.cpp: Auto merged storage/ndb/test/odbc/SQL99_test/SQL99_test.cpp: Auto merged storage/ndb/test/odbc/SQL99_test/SQL99_test.h: Auto merged storage/ndb/test/odbc/client/NDBT_ALLOCHANDLE.cpp: Auto merged storage/ndb/test/odbc/client/NDBT_ALLOCHANDLE_HDBC.cpp: Auto merged storage/ndb/test/odbc/client/NDBT_SQLConnect.cpp: Auto merged storage/ndb/test/odbc/client/NDBT_SQLPrepare.cpp: Auto merged storage/ndb/test/odbc/client/SQLAllocEnvTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLAllocHandleTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLAllocHandleTest_bf.cpp: Auto merged storage/ndb/test/odbc/client/SQLBindColTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLBindParameterTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLCancelTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLCloseCursorTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest1.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest2.cpp: Auto merged storage/ndb/test/odbc/client/SQLColAttributeTest3.cpp: Auto merged storage/ndb/test/odbc/client/SQLConnectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLCopyDescTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLDescribeColTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLDisconnectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLDriverConnectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLEndTranTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLErrorTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLExecDirectTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLExecuteTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFetchScrollTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFetchTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFreeHandleTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLFreeStmtTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetConnectAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetCursorNameTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDataTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDescFieldTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDescRecTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDiagFieldTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDiagRecSimpleTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetDiagRecTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetEnvAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetFunctionsTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetInfoTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetStmtAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLGetTypeInfoTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLMoreResultsTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLNumResultColsTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLParamDataTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLPrepareTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLPutDataTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLRowCountTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetConnectAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetCursorNameTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetDescFieldTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetDescRecTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetEnvAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLSetStmtAttrTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLTablesTest.cpp: Auto merged storage/ndb/test/odbc/client/SQLTransactTest.cpp: Auto merged storage/ndb/test/odbc/client/common.hpp: Auto merged storage/ndb/test/odbc/client/main.cpp: Auto merged storage/ndb/test/odbc/driver/testOdbcDriver.cpp: Auto merged storage/ndb/test/odbc/test_compiler/test_compiler.cpp: Auto merged storage/ndb/test/run-test/main.cpp: Auto merged storage/ndb/test/run-test/run-test.hpp: Auto merged storage/ndb/test/src/CpcClient.cpp: Auto merged storage/ndb/test/src/HugoAsynchTransactions.cpp: Auto merged storage/ndb/test/src/HugoCalculator.cpp: Auto merged storage/ndb/test/src/HugoOperations.cpp: Auto merged storage/ndb/test/src/HugoTransactions.cpp: Auto merged storage/ndb/test/src/NDBT_Error.cpp: Auto merged storage/ndb/test/src/NDBT_Output.cpp: Auto merged storage/ndb/test/src/NDBT_ResultRow.cpp: Auto merged storage/ndb/test/src/NDBT_ReturnCodes.cpp: Auto merged storage/ndb/test/src/NDBT_Table.cpp: Auto merged storage/ndb/test/src/NDBT_Tables.cpp: Auto merged storage/ndb/test/src/NDBT_Test.cpp: Auto merged storage/ndb/test/src/NdbBackup.cpp: Auto merged storage/ndb/test/src/NdbConfig.cpp: Auto merged storage/ndb/test/src/NdbGrep.cpp: Auto merged storage/ndb/test/src/NdbRestarter.cpp: Auto merged storage/ndb/test/src/NdbRestarts.cpp: Auto merged storage/ndb/test/src/NdbSchemaCon.cpp: Auto merged storage/ndb/test/src/NdbSchemaOp.cpp: Auto merged storage/ndb/test/src/UtilTransactions.cpp: Auto merged storage/ndb/test/tools/copy_tab.cpp: Auto merged storage/ndb/test/tools/cpcc.cpp: Auto merged storage/ndb/test/tools/create_index.cpp: Auto merged storage/ndb/test/tools/hugoCalculator.cpp: Auto merged storage/ndb/test/tools/hugoFill.cpp: Auto merged storage/ndb/test/tools/hugoLoad.cpp: Auto merged storage/ndb/test/tools/hugoLockRecords.cpp: Auto merged storage/ndb/test/tools/hugoPkDelete.cpp: Auto merged storage/ndb/test/tools/hugoPkRead.cpp: Auto merged storage/ndb/test/tools/hugoPkReadRecord.cpp: Auto merged storage/ndb/test/tools/hugoPkUpdate.cpp: Auto merged storage/ndb/test/tools/hugoScanRead.cpp: Auto merged storage/ndb/test/tools/hugoScanUpdate.cpp: Auto merged storage/ndb/test/tools/restart.cpp: Auto merged storage/ndb/test/tools/transproxy.cpp: Auto merged storage/ndb/test/tools/verify_index.cpp: Auto merged storage/ndb/tools/delete_all.cpp: Auto merged storage/ndb/tools/desc.cpp: Auto merged storage/ndb/tools/drop_index.cpp: Auto merged storage/ndb/tools/drop_tab.cpp: Auto merged storage/ndb/tools/listTables.cpp: Auto merged storage/ndb/tools/ndb_condig.cpp: Auto merged storage/ndb/tools/ndb_test_platform.cpp: Auto merged storage/ndb/tools/ndbsql.cpp: Auto merged storage/ndb/tools/restore/Restore.cpp: Auto merged storage/ndb/tools/restore/Restore.hpp: Auto merged storage/ndb/tools/restore/consumer.cpp: Auto merged storage/ndb/tools/restore/consumer.hpp: Auto merged storage/ndb/tools/restore/consumer_printer.cpp: Auto merged storage/ndb/tools/restore/consumer_printer.hpp: Auto merged storage/ndb/tools/restore/consumer_restore.cpp: Auto merged storage/ndb/tools/restore/consumer_restore.hpp: Auto merged storage/ndb/tools/restore/consumer_restorem.cpp: Auto merged storage/ndb/tools/restore/restore_main.cpp: Auto merged storage/ndb/tools/select_all.cpp: Auto merged storage/ndb/tools/select_count.cpp: Auto merged storage/ndb/tools/waiter.cpp: Auto merged strings/Makefile.am: Auto merged strings/ctype-big5.c: Auto merged strings/ctype-bin.c: Auto merged strings/ctype-cp932.c: Auto merged strings/ctype-euc_kr.c: Auto merged strings/ctype-eucjpms.c: Auto merged strings/ctype-gb2312.c: Auto merged strings/ctype-gbk.c: Auto merged strings/ctype-latin1.c: Auto merged strings/ctype-mb.c: Auto merged strings/ctype-simple.c: Auto merged strings/ctype-sjis.c: Auto merged strings/ctype-tis620.c: Auto merged strings/ctype-ucs2.c: Auto merged strings/ctype-ujis.c: Auto merged strings/ctype-utf8.c: Auto merged strings/ctype-win1250ch.c: Auto merged strings/ctype.c: Auto merged strings/decimal.c: Auto merged strings/strxnmov.c: Auto merged strings/xml.c: Auto merged tests/Makefile.am: Auto merged tests/mysql_client_test.c: Auto merged vio/Makefile.am: Auto merged vio/vio.c: Auto merged vio/viosocket.c: Auto merged vio/viossl.c: Auto merged vio/viosslfactories.c: Auto merged zlib/Makefile.am: Auto merged
4193 lines
128 KiB
C++
4193 lines
128 KiB
C++
/* Copyright (C) 2000 MySQL AB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
/*
|
|
Description of the query cache:
|
|
|
|
1. Query_cache object consists of
|
|
- query cache memory pool (cache)
|
|
- queries hash (queries)
|
|
- tables hash (tables)
|
|
- list of blocks ordered as they allocated in memory
|
|
(first_block)
|
|
- list of queries block (queries_blocks)
|
|
- list of used tables (tables_blocks)
|
|
|
|
2. Query cache memory pool (cache) consists of
|
|
- table of steps of memory bins allocation
|
|
- table of free memory bins
|
|
- blocks of memory
|
|
|
|
3. Memory blocks
|
|
|
|
Every memory block has the following structure:
|
|
|
|
+----------------------------------------------------------+
|
|
| Block header (Query_cache_block structure) |
|
|
+----------------------------------------------------------+
|
|
|Table of database table lists (used for queries & tables) |
|
|
+----------------------------------------------------------+
|
|
| Type depended header |
|
|
|(Query_cache_query, Query_cache_table, Query_cache_result)|
|
|
+----------------------------------------------------------+
|
|
| Data ... |
|
|
+----------------------------------------------------------+
|
|
|
|
Block header consists of:
|
|
- type:
|
|
FREE Free memory block
|
|
QUERY Query block
|
|
RESULT Ready to send result
|
|
RES_CONT Result's continuation
|
|
RES_BEG First block of results, that is not yet complete,
|
|
written to cache
|
|
RES_INCOMPLETE Allocated for results data block
|
|
TABLE Block with database table description
|
|
INCOMPLETE The destroyed block
|
|
- length of block (length)
|
|
- length of data & headers (used)
|
|
- physical list links (pnext/pprev) - used for the list of
|
|
blocks ordered as they are allocated in physical memory
|
|
- logical list links (next/prev) - used for queries block list, tables block
|
|
list, free memory block lists and list of results block in query
|
|
- number of elements in table of database table list (n_tables)
|
|
|
|
4. Query & results blocks
|
|
|
|
Query stored in cache consists of following blocks:
|
|
|
|
more more
|
|
recent+-------------+ old
|
|
<-----|Query block 1|------> double linked list of queries block
|
|
prev | | next
|
|
+-------------+
|
|
<-| table 0 |-> (see "Table of database table lists" description)
|
|
<-| table 1 |->
|
|
| ... | +--------------------------+
|
|
+-------------+ +-------------------------+ |
|
|
NET | | | V V |
|
|
struct| | +-+------------+ +------------+ |
|
|
<-----|query header |----->|Result block|-->|Result block|-+ doublelinked
|
|
writer| |result| |<--| | list of results
|
|
+-------------+ +------------+ +------------+
|
|
|charset | +------------+ +------------+ no table of dbtables
|
|
|encoding + | | result | | result |
|
|
|query text |<-----| header | | header |------+
|
|
+-------------+parent| | | |parent|
|
|
^ +------------+ +------------+ |
|
|
| |result data | |result data | |
|
|
| +------------+ +------------+ |
|
|
+---------------------------------------------------+
|
|
|
|
First query is registered. During the registration query block is
|
|
allocated. This query block is included in query hash and is linked
|
|
with appropriate database tables lists (if there is no appropriate
|
|
list exists it will be created).
|
|
|
|
Later when query has performed results is written into the result blocks.
|
|
A result block cannot be smaller then QUERY_CACHE_MIN_RESULT_DATA_SIZE.
|
|
|
|
When new result is written to cache it is appended to the last result
|
|
block, if no more free space left in the last block, new block is
|
|
allocated.
|
|
|
|
5. Table of database table lists.
|
|
|
|
For quick invalidation of queries all query are linked in lists on used
|
|
database tables basis (when table will be changed (insert/delete/...)
|
|
this queries will be removed from cache).
|
|
|
|
Root of such list is table block:
|
|
|
|
+------------+ list of used tables (used while invalidation of
|
|
<----| Table |-----> whole database)
|
|
prev| block |next +-----------+
|
|
| | +-----------+ |Query block|
|
|
| | |Query block| +-----------+
|
|
+------------+ +-----------+ | ... |
|
|
+->| table 0 |------>|table 0 |----->| table N |---+
|
|
|+-| |<------| |<-----| |<-+|
|
|
|| +------------+ | ... | | ... | ||
|
|
|| |table header| +-----------+ +-----------+ ||
|
|
|| +------------+ | ... | | ... | ||
|
|
|| |db name + | +-----------+ +-----------+ ||
|
|
|| |table name | ||
|
|
|| +------------+ ||
|
|
|+--------------------------------------------------------+|
|
|
+----------------------------------------------------------+
|
|
|
|
Table block is included into the tables hash (tables).
|
|
|
|
6. Free blocks, free blocks bins & steps of freeblock bins.
|
|
|
|
When we just started only one free memory block existed. All query
|
|
cache memory (that will be used for block allocation) were
|
|
containing in this block.
|
|
When a new block is allocated we find most suitable memory block
|
|
(minimal of >= required size). If such a block can not be found, we try
|
|
to find max block < required size (if we allocate block for results).
|
|
If there is no free memory, oldest query is removed from cache, and then
|
|
we try to allocate memory. Last step should be repeated until we find
|
|
suitable block or until there is no unlocked query found.
|
|
|
|
If the block is found and its length more then we need, it should be
|
|
split into 2 blocks.
|
|
New blocks cannot be smaller then min_allocation_unit_bytes.
|
|
|
|
When a block becomes free, its neighbor-blocks should be tested and if
|
|
there are free blocks among them, they should be joined into one block.
|
|
|
|
Free memory blocks are stored in bins according to their sizes.
|
|
The bins are stored in size-descending order.
|
|
These bins are distributed (by size) approximately logarithmically.
|
|
|
|
First bin (number 0) stores free blocks with
|
|
size <= query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2.
|
|
It is first (number 0) step.
|
|
On the next step distributed (1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
|
|
QUERY_CACHE_MEM_BIN_PARTS_MUL bins. This bins allocated in interval from
|
|
query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 to
|
|
query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 >>
|
|
QUERY_CACHE_MEM_BIN_STEP_PWR2
|
|
...
|
|
On each step interval decreases in 2 power of
|
|
QUERY_CACHE_MEM_BIN_STEP_PWR2
|
|
times, number of bins (that distributed on this step) increases. If on
|
|
the previous step there were N bins distributed , on the current there
|
|
would be distributed
|
|
(N + QUERY_CACHE_MEM_BIN_PARTS_INC) * QUERY_CACHE_MEM_BIN_PARTS_MUL
|
|
bins.
|
|
Last distributed bin stores blocks with size near min_allocation_unit
|
|
bytes.
|
|
|
|
For example:
|
|
query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 = 100,
|
|
min_allocation_unit = 17,
|
|
QUERY_CACHE_MEM_BIN_STEP_PWR2 = 1,
|
|
QUERY_CACHE_MEM_BIN_PARTS_INC = 1,
|
|
QUERY_CACHE_MEM_BIN_PARTS_MUL = 1
|
|
(in followed picture showed right (low) bound of bin):
|
|
|
|
| 100>>1 50>>1 |25>>1|
|
|
| | | | | |
|
|
| 100 75 50 41 33 25 21 18 15| 12 | - bins right (low) bounds
|
|
|
|
|\---/\-----/\--------/\--------|---/ |
|
|
| 0 1 2 3 | | - steps
|
|
\-----------------------------/ \---/
|
|
bins that we store in cache this bin showed for example only
|
|
|
|
|
|
Calculation of steps/bins distribution is performed only when query cache
|
|
is resized.
|
|
|
|
When we need to find appropriate bin, first we should find appropriate
|
|
step, then we should calculate number of bins that are using data
|
|
stored in Query_cache_memory_bin_step structure.
|
|
|
|
Free memory blocks are sorted in bins in lists with size-ascending order
|
|
(more small blocks needed frequently then bigger one).
|
|
|
|
7. Packing cache.
|
|
|
|
Query cache packing is divided into two operation:
|
|
- pack_cache
|
|
- join_results
|
|
|
|
pack_cache moved all blocks to "top" of cache and create one block of free
|
|
space at the "bottom":
|
|
|
|
before pack_cache after pack_cache
|
|
+-------------+ +-------------+
|
|
| query 1 | | query 1 |
|
|
+-------------+ +-------------+
|
|
| table 1 | | table 1 |
|
|
+-------------+ +-------------+
|
|
| results 1.1 | | results 1.1 |
|
|
+-------------+ +-------------+
|
|
| free | | query 2 |
|
|
+-------------+ +-------------+
|
|
| query 2 | | table 2 |
|
|
+-------------+ ---> +-------------+
|
|
| table 2 | | results 1.2 |
|
|
+-------------+ +-------------+
|
|
| results 1.2 | | results 2 |
|
|
+-------------+ +-------------+
|
|
| free | | free |
|
|
+-------------+ | |
|
|
| results 2 | | |
|
|
+-------------+ | |
|
|
| free | | |
|
|
+-------------+ +-------------+
|
|
|
|
pack_cache scan blocks in physical address order and move every non-free
|
|
block "higher".
|
|
|
|
pack_cach remove every free block it finds. The length of the deleted block
|
|
is accumulated to the "gap". All non free blocks should be shifted with the
|
|
"gap" step.
|
|
|
|
join_results scans all complete queries. If the results of query are not
|
|
stored in the same block, join_results tries to move results so, that they
|
|
are stored in one block.
|
|
|
|
before join_results after join_results
|
|
+-------------+ +-------------+
|
|
| query 1 | | query 1 |
|
|
+-------------+ +-------------+
|
|
| table 1 | | table 1 |
|
|
+-------------+ +-------------+
|
|
| results 1.1 | | free |
|
|
+-------------+ +-------------+
|
|
| query 2 | | query 2 |
|
|
+-------------+ +-------------+
|
|
| table 2 | | table 2 |
|
|
+-------------+ ---> +-------------+
|
|
| results 1.2 | | free |
|
|
+-------------+ +-------------+
|
|
| results 2 | | results 2 |
|
|
+-------------+ +-------------+
|
|
| free | | results 1 |
|
|
| | | |
|
|
| | +-------------+
|
|
| | | free |
|
|
| | | |
|
|
+-------------+ +-------------+
|
|
|
|
If join_results allocated new block(s) then we need call pack_cache again.
|
|
|
|
TODO list:
|
|
|
|
- Delayed till after-parsing qache answer (for column rights processing)
|
|
- Optimize cache resizing
|
|
- if new_size < old_size then pack & shrink
|
|
- if new_size > old_size copy cached query to new cache
|
|
- Move MRG_MYISAM table type processing to handlers, something like:
|
|
tables_used->table->file->register_used_filenames(callback,
|
|
first_argument);
|
|
- QC improvement suggested by Monty:
|
|
- Add a counter in open_table() for how many MERGE (ISAM or MyISAM)
|
|
tables are cached in the table cache.
|
|
(This will be trivial when we have the new table cache in place I
|
|
have been working on)
|
|
- After this we can add the following test around the for loop in
|
|
is_cacheable::
|
|
|
|
if (thd->temp_tables || global_merge_table_count)
|
|
|
|
- Another option would be to set thd->lex->safe_to_cache_query to 0
|
|
in 'get_lock_data' if any of the tables was a tmp table or a
|
|
MRG_ISAM table.
|
|
(This could be done with almost no speed penalty)
|
|
*/
|
|
|
|
#include "mysql_priv.h"
|
|
#ifdef HAVE_QUERY_CACHE
|
|
#include <m_ctype.h>
|
|
#include <my_dir.h>
|
|
#include <hash.h>
|
|
#include "../storage/myisammrg/ha_myisammrg.h"
|
|
#include "../storage/myisammrg/myrg_def.h"
|
|
|
|
#ifdef EMBEDDED_LIBRARY
|
|
#include "emb_qcache.h"
|
|
#endif
|
|
|
|
#if !defined(EXTRA_DBUG) && !defined(DBUG_OFF)
|
|
#define MUTEX_LOCK(M) { DBUG_PRINT("lock", ("mutex lock 0x%lx", (ulong)(M))); \
|
|
pthread_mutex_lock(M);}
|
|
#define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\
|
|
(ulong)(M))); pthread_mutex_unlock(M);}
|
|
#define RW_WLOCK(M) {DBUG_PRINT("lock", ("rwlock wlock 0x%lx",(ulong)(M))); \
|
|
if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")); \
|
|
else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); }
|
|
#define RW_RLOCK(M) {DBUG_PRINT("lock", ("rwlock rlock 0x%lx", (ulong)(M))); \
|
|
if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")); \
|
|
else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); }
|
|
#define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \
|
|
if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \
|
|
else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); }
|
|
#define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \
|
|
pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));}
|
|
#define STRUCT_UNLOCK(M) { \
|
|
DBUG_PRINT("lock", ("%d struct unlock...",__LINE__)); \
|
|
pthread_mutex_unlock(M);DBUG_PRINT("lock", ("struct unlock OK"));}
|
|
#define BLOCK_LOCK_WR(B) {DBUG_PRINT("lock", ("%d LOCK_WR 0x%lx",\
|
|
__LINE__,(ulong)(B))); \
|
|
B->query()->lock_writing();}
|
|
#define BLOCK_LOCK_RD(B) {DBUG_PRINT("lock", ("%d LOCK_RD 0x%lx",\
|
|
__LINE__,(ulong)(B))); \
|
|
B->query()->lock_reading();}
|
|
#define BLOCK_UNLOCK_WR(B) { \
|
|
DBUG_PRINT("lock", ("%d UNLOCK_WR 0x%lx",\
|
|
__LINE__,(ulong)(B)));B->query()->unlock_writing();}
|
|
#define BLOCK_UNLOCK_RD(B) { \
|
|
DBUG_PRINT("lock", ("%d UNLOCK_RD 0x%lx",\
|
|
__LINE__,(ulong)(B)));B->query()->unlock_reading();}
|
|
#define DUMP(C) DBUG_EXECUTE("qcache", {\
|
|
(C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();})
|
|
#else
|
|
#define MUTEX_LOCK(M) pthread_mutex_lock(M)
|
|
#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
|
|
#define RW_WLOCK(M) rw_wrlock(M)
|
|
#define RW_RLOCK(M) rw_rdlock(M)
|
|
#define RW_UNLOCK(M) rw_unlock(M)
|
|
#define STRUCT_LOCK(M) pthread_mutex_lock(M)
|
|
#define STRUCT_UNLOCK(M) pthread_mutex_unlock(M)
|
|
#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
|
|
#define BLOCK_LOCK_RD(B) B->query()->lock_reading()
|
|
#define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
|
|
#define BLOCK_UNLOCK_RD(B) B->query()->unlock_reading()
|
|
#define DUMP(C)
|
|
#endif
|
|
|
|
const char *query_cache_type_names[]= { "OFF", "ON", "DEMAND",NullS };
|
|
TYPELIB query_cache_type_typelib=
|
|
{
|
|
array_elements(query_cache_type_names)-1,"", query_cache_type_names, NULL
|
|
};
|
|
|
|
/*****************************************************************************
|
|
Query_cache_block_table method(s)
|
|
*****************************************************************************/
|
|
|
|
inline Query_cache_block * Query_cache_block_table::block()
|
|
{
|
|
return (Query_cache_block *)(((byte*)this) -
|
|
ALIGN_SIZE(sizeof(Query_cache_block_table)*n) -
|
|
ALIGN_SIZE(sizeof(Query_cache_block)));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Query_cache_block method(s)
|
|
*****************************************************************************/
|
|
|
|
void Query_cache_block::init(ulong block_length)
|
|
{
|
|
DBUG_ENTER("Query_cache_block::init");
|
|
DBUG_PRINT("qcache", ("init block 0x%lx length: %lu", (ulong) this,
|
|
block_length));
|
|
length = block_length;
|
|
used = 0;
|
|
type = Query_cache_block::FREE;
|
|
n_tables = 0;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void Query_cache_block::destroy()
|
|
{
|
|
DBUG_ENTER("Query_cache_block::destroy");
|
|
DBUG_PRINT("qcache", ("destroy block 0x%lx, type %d",
|
|
(ulong) this, type));
|
|
type = INCOMPLETE;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
inline uint Query_cache_block::headers_len()
|
|
{
|
|
return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
|
|
ALIGN_SIZE(sizeof(Query_cache_block)));
|
|
}
|
|
|
|
inline gptr Query_cache_block::data(void)
|
|
{
|
|
return (gptr)( ((byte*)this) + headers_len() );
|
|
}
|
|
|
|
inline Query_cache_query * Query_cache_block::query()
|
|
{
|
|
#ifndef DBUG_OFF
|
|
if (type != QUERY)
|
|
query_cache.wreck(__LINE__, "incorrect block type");
|
|
#endif
|
|
return (Query_cache_query *) data();
|
|
}
|
|
|
|
inline Query_cache_table * Query_cache_block::table()
|
|
{
|
|
#ifndef DBUG_OFF
|
|
if (type != TABLE)
|
|
query_cache.wreck(__LINE__, "incorrect block type");
|
|
#endif
|
|
return (Query_cache_table *) data();
|
|
}
|
|
|
|
inline Query_cache_result * Query_cache_block::result()
|
|
{
|
|
#ifndef DBUG_OFF
|
|
if (type != RESULT && type != RES_CONT && type != RES_BEG &&
|
|
type != RES_INCOMPLETE)
|
|
query_cache.wreck(__LINE__, "incorrect block type");
|
|
#endif
|
|
return (Query_cache_result *) data();
|
|
}
|
|
|
|
inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
|
|
{
|
|
return ((Query_cache_block_table *)
|
|
(((byte*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
|
|
n*sizeof(Query_cache_block_table)));
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* Query_cache_table method(s)
|
|
*****************************************************************************/
|
|
|
|
extern "C"
|
|
{
|
|
byte *query_cache_table_get_key(const byte *record, uint *length,
|
|
my_bool not_used __attribute__((unused)))
|
|
{
|
|
Query_cache_block* table_block = (Query_cache_block*) record;
|
|
*length = (table_block->used - table_block->headers_len() -
|
|
ALIGN_SIZE(sizeof(Query_cache_table)));
|
|
return (((byte *) table_block->data()) +
|
|
ALIGN_SIZE(sizeof(Query_cache_table)));
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Query_cache_query methods
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
Following methods work for block read/write locking only in this
|
|
particular case and in interaction with structure_guard_mutex.
|
|
|
|
Lock for write prevents any other locking. (exclusive use)
|
|
Lock for read prevents only locking for write.
|
|
*/
|
|
|
|
inline void Query_cache_query::lock_writing()
|
|
{
|
|
RW_WLOCK(&lock);
|
|
}
|
|
|
|
|
|
/*
|
|
Needed for finding queries, that we may delete from cache.
|
|
We don't want to wait while block become unlocked. In addition,
|
|
block locking means that query is now used and we don't need to
|
|
remove it.
|
|
*/
|
|
|
|
my_bool Query_cache_query::try_lock_writing()
|
|
{
|
|
DBUG_ENTER("Query_cache_block::try_lock_writing");
|
|
if (rw_trywrlock(&lock)!=0)
|
|
{
|
|
DBUG_PRINT("info", ("can't lock rwlock"));
|
|
DBUG_RETURN(0);
|
|
}
|
|
DBUG_PRINT("info", ("rwlock 0x%lx locked", (ulong) &lock));
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
|
|
inline void Query_cache_query::lock_reading()
|
|
{
|
|
RW_RLOCK(&lock);
|
|
}
|
|
|
|
|
|
inline void Query_cache_query::unlock_writing()
|
|
{
|
|
RW_UNLOCK(&lock);
|
|
}
|
|
|
|
|
|
inline void Query_cache_query::unlock_reading()
|
|
{
|
|
RW_UNLOCK(&lock);
|
|
}
|
|
|
|
|
|
void Query_cache_query::init_n_lock()
|
|
{
|
|
DBUG_ENTER("Query_cache_query::init_n_lock");
|
|
res=0; wri = 0; len = 0;
|
|
my_rwlock_init(&lock, NULL);
|
|
lock_writing();
|
|
DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
|
|
(long) (((byte*) this) -
|
|
ALIGN_SIZE(sizeof(Query_cache_block)))));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void Query_cache_query::unlock_n_destroy()
|
|
{
|
|
DBUG_ENTER("Query_cache_query::unlock_n_destroy");
|
|
DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
|
|
(long) (((byte*) this) -
|
|
ALIGN_SIZE(sizeof(Query_cache_block)))));
|
|
/*
|
|
The following call is not needed on system where one can destroy an
|
|
active semaphore
|
|
*/
|
|
this->unlock_writing();
|
|
rwlock_destroy(&lock);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
extern "C"
|
|
{
|
|
byte *query_cache_query_get_key(const byte *record, uint *length,
|
|
my_bool not_used)
|
|
{
|
|
Query_cache_block *query_block = (Query_cache_block*) record;
|
|
*length = (query_block->used - query_block->headers_len() -
|
|
ALIGN_SIZE(sizeof(Query_cache_query)));
|
|
return (((byte *) query_block->data()) +
|
|
ALIGN_SIZE(sizeof(Query_cache_query)));
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Functions to store things into the query cache
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
Note on double-check locking (DCL) usage.
|
|
|
|
Below, in query_cache_insert(), query_cache_abort() and
|
|
query_cache_end_of_result() we use what is called double-check
|
|
locking (DCL) for NET::query_cache_query. I.e. we test it first
|
|
without a lock, and, if positive, test again under the lock.
|
|
|
|
This means that if we see 'NET::query_cache_query == 0' without a
|
|
lock we will skip the operation. But this is safe here: when we
|
|
started to cache a query, we called Query_cache::store_query(), and
|
|
NET::query_cache_query was set to non-zero in this thread (and the
|
|
thread always sees results of its memory operations, mutex or not).
|
|
If later we see 'NET::query_cache_query == 0' without locking a
|
|
mutex, that may only mean that some other thread have reset it by
|
|
invalidating the query. Skipping the operation in this case is the
|
|
right thing to do, as NET::query_cache_query won't get non-zero for
|
|
this query again.
|
|
|
|
See also comments in Query_cache::store_query() and
|
|
Query_cache::send_result_to_client().
|
|
|
|
NOTE, however, that double-check locking is not applicable in
|
|
'invalidate' functions, as we may erroneously skip invalidation,
|
|
because the thread doing invalidation may never see non-zero
|
|
NET::query_cache_query.
|
|
*/
|
|
|
|
|
|
void query_cache_init_query(NET *net)
|
|
{
|
|
/*
|
|
It is safe to initialize 'NET::query_cache_query' without a lock
|
|
here, because before it will be accessed from different threads it
|
|
will be set in this thread under a lock, and access from the same
|
|
thread is always safe.
|
|
*/
|
|
net->query_cache_query= 0;
|
|
}
|
|
|
|
|
|
/*
|
|
Insert the packet into the query cache.
|
|
*/
|
|
|
|
void query_cache_insert(NET *net, const char *packet, ulong length)
|
|
{
|
|
DBUG_ENTER("query_cache_insert");
|
|
|
|
/* See the comment on double-check locking usage above. */
|
|
if (net->query_cache_query == 0)
|
|
DBUG_VOID_RETURN;
|
|
|
|
STRUCT_LOCK(&query_cache.structure_guard_mutex);
|
|
|
|
if (unlikely(query_cache.query_cache_size == 0 ||
|
|
query_cache.flush_in_progress))
|
|
{
|
|
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
Query_cache_block *query_block = ((Query_cache_block*)
|
|
net->query_cache_query);
|
|
if (query_block)
|
|
{
|
|
Query_cache_query *header = query_block->query();
|
|
Query_cache_block *result = header->result();
|
|
|
|
DUMP(&query_cache);
|
|
BLOCK_LOCK_WR(query_block);
|
|
DBUG_PRINT("qcache", ("insert packet %lu bytes long",length));
|
|
|
|
/*
|
|
On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be
|
|
done by query_cache.append_result_data if success (if not we need
|
|
query_cache.structure_guard_mutex locked to free query)
|
|
*/
|
|
if (!query_cache.append_result_data(&result, length, (gptr) packet,
|
|
query_block))
|
|
{
|
|
DBUG_PRINT("warning", ("Can't append data"));
|
|
header->result(result);
|
|
DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block));
|
|
// The following call will remove the lock on query_block
|
|
query_cache.free_query(query_block);
|
|
// append_result_data no success => we need unlock
|
|
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
header->result(result);
|
|
header->last_pkt_nr= net->pkt_nr;
|
|
BLOCK_UNLOCK_WR(query_block);
|
|
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
|
|
}
|
|
else
|
|
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void query_cache_abort(NET *net)
|
|
{
|
|
DBUG_ENTER("query_cache_abort");
|
|
|
|
/* See the comment on double-check locking usage above. */
|
|
if (net->query_cache_query == 0)
|
|
DBUG_VOID_RETURN;
|
|
|
|
STRUCT_LOCK(&query_cache.structure_guard_mutex);
|
|
|
|
if (unlikely(query_cache.query_cache_size == 0 ||
|
|
query_cache.flush_in_progress))
|
|
{
|
|
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
Query_cache_block *query_block= ((Query_cache_block*)
|
|
net->query_cache_query);
|
|
if (query_block) // Test if changed by other thread
|
|
{
|
|
DUMP(&query_cache);
|
|
BLOCK_LOCK_WR(query_block);
|
|
// The following call will remove the lock on query_block
|
|
query_cache.free_query(query_block);
|
|
net->query_cache_query= 0;
|
|
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
|
}
|
|
|
|
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void query_cache_end_of_result(THD *thd)
|
|
{
|
|
Query_cache_block *query_block;
|
|
DBUG_ENTER("query_cache_end_of_result");
|
|
|
|
/* See the comment on double-check locking usage above. */
|
|
if (thd->net.query_cache_query == 0)
|
|
DBUG_VOID_RETURN;
|
|
|
|
#ifdef EMBEDDED_LIBRARY
|
|
query_cache_insert(&thd->net, (char*)thd,
|
|
emb_count_querycache_size(thd));
|
|
#endif
|
|
|
|
STRUCT_LOCK(&query_cache.structure_guard_mutex);
|
|
|
|
if (unlikely(query_cache.query_cache_size == 0 ||
|
|
query_cache.flush_in_progress))
|
|
goto end;
|
|
|
|
query_block= ((Query_cache_block*) thd->net.query_cache_query);
|
|
if (query_block)
|
|
{
|
|
DUMP(&query_cache);
|
|
BLOCK_LOCK_WR(query_block);
|
|
Query_cache_query *header= query_block->query();
|
|
Query_cache_block *last_result_block= header->result()->prev;
|
|
ulong allign_size= ALIGN_SIZE(last_result_block->used);
|
|
ulong len= max(query_cache.min_allocation_unit, allign_size);
|
|
if (last_result_block->length >= query_cache.min_allocation_unit + len)
|
|
query_cache.split_block(last_result_block,len);
|
|
|
|
#ifndef DBUG_OFF
|
|
if (header->result() == 0)
|
|
{
|
|
DBUG_PRINT("error", ("end of data whith no result. query '%s'",
|
|
header->query()));
|
|
query_cache.wreck(__LINE__, "");
|
|
|
|
/*
|
|
We do not need call of BLOCK_UNLOCK_WR(query_block); here because
|
|
query_cache.wreck() switched query cache off but left content
|
|
untouched for investigation (it is debugging method).
|
|
*/
|
|
goto end;
|
|
}
|
|
#endif
|
|
header->found_rows(current_thd->limit_found_rows);
|
|
header->result()->type= Query_cache_block::RESULT;
|
|
header->writer(0);
|
|
thd->net.query_cache_query= 0;
|
|
BLOCK_UNLOCK_WR(query_block);
|
|
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
|
|
|
}
|
|
|
|
end:
|
|
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void query_cache_invalidate_by_MyISAM_filename(const char *filename)
|
|
{
|
|
query_cache.invalidate_by_MyISAM_filename(filename);
|
|
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Query_cache methods
|
|
*****************************************************************************/
|
|
|
|
Query_cache::Query_cache(ulong query_cache_limit_arg,
|
|
ulong min_allocation_unit_arg,
|
|
ulong min_result_data_size_arg,
|
|
uint def_query_hash_size_arg,
|
|
uint def_table_hash_size_arg)
|
|
:query_cache_size(0),
|
|
query_cache_limit(query_cache_limit_arg),
|
|
queries_in_cache(0), hits(0), inserts(0), refused(0),
|
|
total_blocks(0), lowmem_prunes(0),
|
|
min_allocation_unit(ALIGN_SIZE(min_allocation_unit_arg)),
|
|
min_result_data_size(ALIGN_SIZE(min_result_data_size_arg)),
|
|
def_query_hash_size(ALIGN_SIZE(def_query_hash_size_arg)),
|
|
def_table_hash_size(ALIGN_SIZE(def_table_hash_size_arg)),
|
|
initialized(0)
|
|
{
|
|
ulong min_needed= (ALIGN_SIZE(sizeof(Query_cache_block)) +
|
|
ALIGN_SIZE(sizeof(Query_cache_block_table)) +
|
|
ALIGN_SIZE(sizeof(Query_cache_query)) + 3);
|
|
set_if_bigger(min_allocation_unit,min_needed);
|
|
this->min_allocation_unit= ALIGN_SIZE(min_allocation_unit);
|
|
set_if_bigger(this->min_result_data_size,min_allocation_unit);
|
|
}
|
|
|
|
|
|
ulong Query_cache::resize(ulong query_cache_size_arg)
|
|
{
|
|
DBUG_ENTER("Query_cache::resize");
|
|
DBUG_PRINT("qcache", ("from %lu to %lu",query_cache_size,
|
|
query_cache_size_arg));
|
|
DBUG_ASSERT(initialized);
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
free_cache();
|
|
query_cache_size= query_cache_size_arg;
|
|
::query_cache_size= init_cache();
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_RETURN(::query_cache_size);
|
|
}
|
|
|
|
|
|
ulong Query_cache::set_min_res_unit(ulong size)
|
|
{
|
|
if (size < min_allocation_unit)
|
|
size= min_allocation_unit;
|
|
return (min_result_data_size= ALIGN_SIZE(size));
|
|
}
|
|
|
|
|
|
void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
|
|
{
|
|
TABLE_COUNTER_TYPE local_tables;
|
|
ulong tot_length;
|
|
DBUG_ENTER("Query_cache::store_query");
|
|
/*
|
|
Testing 'query_cache_size' without a lock here is safe: the thing
|
|
we may loose is that the query won't be cached, but we save on
|
|
mutex locking in the case when query cache is disabled or the
|
|
query is uncachable.
|
|
|
|
See also a note on double-check locking usage above.
|
|
*/
|
|
if (thd->locked_tables || query_cache_size == 0)
|
|
DBUG_VOID_RETURN;
|
|
uint8 tables_type= 0;
|
|
|
|
if ((local_tables= is_cacheable(thd, thd->query_length,
|
|
thd->query, thd->lex, tables_used,
|
|
&tables_type)))
|
|
{
|
|
NET *net= &thd->net;
|
|
Query_cache_query_flags flags;
|
|
// fill all gaps between fields with 0 to get repeatable key
|
|
bzero(&flags, QUERY_CACHE_FLAGS_SIZE);
|
|
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
|
|
flags.client_protocol_41= test(thd->client_capabilities &
|
|
CLIENT_PROTOCOL_41);
|
|
flags.more_results_exists= test(thd->server_status &
|
|
SERVER_MORE_RESULTS_EXISTS);
|
|
flags.pkt_nr= net->pkt_nr;
|
|
flags.character_set_client_num=
|
|
thd->variables.character_set_client->number;
|
|
flags.character_set_results_num=
|
|
(thd->variables.character_set_results ?
|
|
thd->variables.character_set_results->number :
|
|
UINT_MAX);
|
|
flags.collation_connection_num=
|
|
thd->variables.collation_connection->number;
|
|
flags.limit= thd->variables.select_limit;
|
|
flags.time_zone= thd->variables.time_zone;
|
|
flags.sql_mode= thd->variables.sql_mode;
|
|
flags.max_sort_length= thd->variables.max_sort_length;
|
|
flags.lc_time_names= thd->variables.lc_time_names;
|
|
flags.group_concat_max_len= thd->variables.group_concat_max_len;
|
|
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
|
|
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
|
|
sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
|
|
(int)flags.client_long_flag,
|
|
(int)flags.client_protocol_41,
|
|
(int)flags.more_results_exists,
|
|
flags.pkt_nr,
|
|
flags.character_set_client_num,
|
|
flags.character_set_results_num,
|
|
flags.collation_connection_num,
|
|
(ulong) flags.limit,
|
|
(ulong) flags.time_zone,
|
|
flags.sql_mode,
|
|
flags.max_sort_length,
|
|
flags.group_concat_max_len));
|
|
/*
|
|
Make InnoDB to release the adaptive hash index latch before
|
|
acquiring the query cache mutex.
|
|
*/
|
|
ha_release_temporary_latches(thd);
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size == 0 || flush_in_progress)
|
|
{
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
DUMP(this);
|
|
|
|
if (ask_handler_allowance(thd, tables_used))
|
|
{
|
|
refused++;
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/* Key is query + database + flag */
|
|
if (thd->db_length)
|
|
{
|
|
memcpy(thd->query+thd->query_length+1, thd->db, thd->db_length);
|
|
DBUG_PRINT("qcache", ("database: %s length: %u",
|
|
thd->db, thd->db_length));
|
|
}
|
|
else
|
|
{
|
|
DBUG_PRINT("qcache", ("No active database"));
|
|
}
|
|
tot_length= thd->query_length + thd->db_length + 1 +
|
|
QUERY_CACHE_FLAGS_SIZE;
|
|
/*
|
|
We should only copy structure (don't use it location directly)
|
|
because of alignment issue
|
|
*/
|
|
memcpy((void *)(thd->query + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
|
|
&flags, QUERY_CACHE_FLAGS_SIZE);
|
|
|
|
/* Check if another thread is processing the same query? */
|
|
Query_cache_block *competitor = (Query_cache_block *)
|
|
hash_search(&queries, (byte*) thd->query, tot_length);
|
|
DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor));
|
|
if (competitor == 0)
|
|
{
|
|
/* Query is not in cache and no one is working with it; Store it */
|
|
Query_cache_block *query_block;
|
|
query_block= write_block_data(tot_length, (gptr) thd->query,
|
|
ALIGN_SIZE(sizeof(Query_cache_query)),
|
|
Query_cache_block::QUERY, local_tables, 1);
|
|
if (query_block != 0)
|
|
{
|
|
DBUG_PRINT("qcache", ("query block 0x%lx allocated, %lu",
|
|
(ulong) query_block, query_block->used));
|
|
|
|
Query_cache_query *header = query_block->query();
|
|
header->init_n_lock();
|
|
if (my_hash_insert(&queries, (byte*) query_block))
|
|
{
|
|
refused++;
|
|
DBUG_PRINT("qcache", ("insertion in query hash"));
|
|
header->unlock_n_destroy();
|
|
free_memory_block(query_block);
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
goto end;
|
|
}
|
|
if (!register_all_tables(query_block, tables_used, local_tables))
|
|
{
|
|
refused++;
|
|
DBUG_PRINT("warning", ("tables list including failed"));
|
|
hash_delete(&queries, (byte *) query_block);
|
|
header->unlock_n_destroy();
|
|
free_memory_block(query_block);
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
goto end;
|
|
}
|
|
double_linked_list_simple_include(query_block, &queries_blocks);
|
|
inserts++;
|
|
queries_in_cache++;
|
|
net->query_cache_query= (gptr) query_block;
|
|
header->writer(net);
|
|
header->tables_type(tables_type);
|
|
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
// init_n_lock make query block locked
|
|
BLOCK_UNLOCK_WR(query_block);
|
|
}
|
|
else
|
|
{
|
|
// We have not enough memory to store query => do nothing
|
|
refused++;
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_PRINT("warning", ("Can't allocate query"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Another thread is processing the same query => do nothing
|
|
refused++;
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_PRINT("qcache", ("Another thread process same query"));
|
|
}
|
|
}
|
|
else if (thd->lex->sql_command == SQLCOM_SELECT)
|
|
statistic_increment(refused, &structure_guard_mutex);
|
|
|
|
end:
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Check if the query is in the cache. If it was cached, send it
|
|
to the user.
|
|
|
|
RESULTS
|
|
1 Query was not cached.
|
|
0 The query was cached and user was sent the result.
|
|
-1 The query was cached but we didn't have rights to use it.
|
|
No error is sent to the client yet.
|
|
|
|
NOTE
|
|
This method requires that sql points to allocated memory of size:
|
|
tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
|
|
*/
|
|
|
|
int
|
|
Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
|
|
{
|
|
ulonglong engine_data;
|
|
Query_cache_query *query;
|
|
Query_cache_block *first_result_block, *result_block;
|
|
Query_cache_block_table *block_table, *block_table_end;
|
|
ulong tot_length;
|
|
Query_cache_query_flags flags;
|
|
DBUG_ENTER("Query_cache::send_result_to_client");
|
|
|
|
/*
|
|
Testing 'query_cache_size' without a lock here is safe: the thing
|
|
we may loose is that the query won't be served from cache, but we
|
|
save on mutex locking in the case when query cache is disabled.
|
|
|
|
See also a note on double-check locking usage above.
|
|
*/
|
|
if (thd->locked_tables || thd->variables.query_cache_type == 0 ||
|
|
query_cache_size == 0)
|
|
goto err;
|
|
|
|
if (!thd->lex->safe_to_cache_query)
|
|
{
|
|
DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
|
|
goto err;
|
|
}
|
|
|
|
{
|
|
uint i= 0;
|
|
/*
|
|
Skip '(' characters in queries like following:
|
|
(select a from t1) union (select a from t1);
|
|
*/
|
|
while (sql[i]=='(')
|
|
i++;
|
|
|
|
/*
|
|
Test if the query is a SELECT
|
|
(pre-space is removed in dispatch_command).
|
|
|
|
First '/' looks like comment before command it is not
|
|
frequently appeared in real life, consequently we can
|
|
check all such queries, too.
|
|
*/
|
|
if ((my_toupper(system_charset_info, sql[i]) != 'S' ||
|
|
my_toupper(system_charset_info, sql[i + 1]) != 'E' ||
|
|
my_toupper(system_charset_info, sql[i + 2]) != 'L') &&
|
|
sql[i] != '/')
|
|
{
|
|
DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size == 0 || flush_in_progress)
|
|
{
|
|
DBUG_PRINT("qcache", ("query cache disabled"));
|
|
goto err_unlock;
|
|
}
|
|
|
|
/* Check that we haven't forgot to reset the query cache variables */
|
|
DBUG_ASSERT(thd->net.query_cache_query == 0);
|
|
|
|
Query_cache_block *query_block;
|
|
|
|
tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
|
|
if (thd->db_length)
|
|
{
|
|
memcpy(sql+query_length+1, thd->db, thd->db_length);
|
|
DBUG_PRINT("qcache", ("database: '%s' length: %u",
|
|
thd->db, thd->db_length));
|
|
}
|
|
else
|
|
{
|
|
DBUG_PRINT("qcache", ("No active database"));
|
|
}
|
|
|
|
// fill all gaps between fields with 0 to get repeatable key
|
|
bzero(&flags, QUERY_CACHE_FLAGS_SIZE);
|
|
flags.client_long_flag= test(thd->client_capabilities & CLIENT_LONG_FLAG);
|
|
flags.client_protocol_41= test(thd->client_capabilities &
|
|
CLIENT_PROTOCOL_41);
|
|
flags.more_results_exists= test(thd->server_status &
|
|
SERVER_MORE_RESULTS_EXISTS);
|
|
flags.pkt_nr= thd->net.pkt_nr;
|
|
flags.character_set_client_num= thd->variables.character_set_client->number;
|
|
flags.character_set_results_num=
|
|
(thd->variables.character_set_results ?
|
|
thd->variables.character_set_results->number :
|
|
UINT_MAX);
|
|
flags.collation_connection_num= thd->variables.collation_connection->number;
|
|
flags.limit= thd->variables.select_limit;
|
|
flags.time_zone= thd->variables.time_zone;
|
|
flags.sql_mode= thd->variables.sql_mode;
|
|
flags.max_sort_length= thd->variables.max_sort_length;
|
|
flags.group_concat_max_len= thd->variables.group_concat_max_len;
|
|
flags.lc_time_names= thd->variables.lc_time_names;
|
|
DBUG_PRINT("qcache", ("long %d, 4.1: %d, more results %d, pkt_nr: %d, \
|
|
CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
|
|
sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
|
|
(int)flags.client_long_flag,
|
|
(int)flags.client_protocol_41,
|
|
(int)flags.more_results_exists,
|
|
flags.pkt_nr,
|
|
flags.character_set_client_num,
|
|
flags.character_set_results_num,
|
|
flags.collation_connection_num,
|
|
(ulong) flags.limit,
|
|
(ulong) flags.time_zone,
|
|
flags.sql_mode,
|
|
flags.max_sort_length,
|
|
flags.group_concat_max_len));
|
|
memcpy((void *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
|
|
&flags, QUERY_CACHE_FLAGS_SIZE);
|
|
query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql,
|
|
tot_length);
|
|
/* Quick abort on unlocked data */
|
|
if (query_block == 0 ||
|
|
query_block->query()->result() == 0 ||
|
|
query_block->query()->result()->type != Query_cache_block::RESULT)
|
|
{
|
|
DBUG_PRINT("qcache", ("No query in query hash or no results"));
|
|
goto err_unlock;
|
|
}
|
|
DBUG_PRINT("qcache", ("Query in query hash 0x%lx", (ulong)query_block));
|
|
|
|
/* Now lock and test that nothing changed while blocks was unlocked */
|
|
BLOCK_LOCK_RD(query_block);
|
|
|
|
query = query_block->query();
|
|
result_block= first_result_block= query->result();
|
|
|
|
if (result_block == 0 || result_block->type != Query_cache_block::RESULT)
|
|
{
|
|
/* The query is probably yet processed */
|
|
DBUG_PRINT("qcache", ("query found, but no data or data incomplete"));
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
goto err_unlock;
|
|
}
|
|
DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query));
|
|
|
|
if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
|
|
(query->tables_type() & HA_CACHE_TBL_TRANSACT))
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("we are in transaction and have transaction tables in query"));
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
goto err_unlock;
|
|
}
|
|
|
|
// Check access;
|
|
block_table= query_block->table(0);
|
|
block_table_end= block_table+query_block->n_tables;
|
|
for (; block_table != block_table_end; block_table++)
|
|
{
|
|
TABLE_LIST table_list;
|
|
TABLE *tmptable;
|
|
Query_cache_table *table = block_table->parent;
|
|
|
|
/*
|
|
Check that we have not temporary tables with same names of tables
|
|
of this query. If we have such tables, we will not send data from
|
|
query cache, because temporary tables hide real tables by which
|
|
query in query cache was made.
|
|
*/
|
|
for (tmptable= thd->temporary_tables; tmptable ; tmptable= tmptable->next)
|
|
{
|
|
if (tmptable->s->table_cache_key.length - TMP_TABLE_KEY_EXTRA ==
|
|
table->key_length() &&
|
|
!memcmp(tmptable->s->table_cache_key.str, table->data(),
|
|
table->key_length()))
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("Temporary table detected: '%s.%s'",
|
|
table_list.db, table_list.alias));
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
/*
|
|
We should not store result of this query because it contain
|
|
temporary tables => assign following variable to make check
|
|
faster.
|
|
*/
|
|
thd->lex->safe_to_cache_query=0;
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
}
|
|
|
|
bzero((char*) &table_list,sizeof(table_list));
|
|
table_list.db = table->db();
|
|
table_list.alias= table_list.table_name= table->table();
|
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
if (check_table_access(thd,SELECT_ACL,&table_list,1))
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("probably no SELECT access to %s.%s => return to normal processing",
|
|
table_list.db, table_list.alias));
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
thd->lex->safe_to_cache_query=0; // Don't try to cache this
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
DBUG_RETURN(-1); // Privilege error
|
|
}
|
|
if (table_list.grant.want_privilege)
|
|
{
|
|
DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
|
|
table_list.db, table_list.alias));
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
thd->lex->safe_to_cache_query= 0; // Don't try to cache this
|
|
goto err_unlock; // Parse query
|
|
}
|
|
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
|
|
engine_data= table->engine_data();
|
|
if (table->callback() &&
|
|
!(*table->callback())(thd, table->db(),
|
|
table->key_length(),
|
|
&engine_data))
|
|
{
|
|
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
|
|
table_list.db, table_list.alias));
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
if (engine_data != table->engine_data())
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("Handler require invalidation queries of %s.%s %lu-%lu",
|
|
table_list.db, table_list.alias,
|
|
(ulong) engine_data, (ulong) table->engine_data()));
|
|
invalidate_table((byte *) table->db(), table->key_length());
|
|
}
|
|
else
|
|
thd->lex->safe_to_cache_query= 0; // Don't try to cache this
|
|
goto err_unlock; // Parse query
|
|
}
|
|
else
|
|
DBUG_PRINT("qcache", ("handler allow caching %s,%s",
|
|
table_list.db, table_list.alias));
|
|
}
|
|
move_to_query_list_end(query_block);
|
|
hits++;
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
/*
|
|
Send cached result to client
|
|
*/
|
|
#ifndef EMBEDDED_LIBRARY
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)",
|
|
result_block->length, result_block->used,
|
|
(ulong) (result_block->headers_len()+
|
|
ALIGN_SIZE(sizeof(Query_cache_result)))));
|
|
|
|
Query_cache_result *result = result_block->result();
|
|
if (net_real_write(&thd->net, result->data(),
|
|
result_block->used -
|
|
result_block->headers_len() -
|
|
ALIGN_SIZE(sizeof(Query_cache_result))))
|
|
break; // Client aborted
|
|
result_block = result_block->next;
|
|
thd->net.pkt_nr= query->last_pkt_nr; // Keep packet number updated
|
|
} while (result_block != first_result_block);
|
|
#else
|
|
{
|
|
Querycache_stream qs(result_block, result_block->headers_len() +
|
|
ALIGN_SIZE(sizeof(Query_cache_result)));
|
|
emb_load_querycache_result(thd, &qs);
|
|
}
|
|
#endif /*!EMBEDDED_LIBRARY*/
|
|
|
|
thd->limit_found_rows = query->found_rows();
|
|
thd->status_var.last_query_cost= 0.0;
|
|
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
DBUG_RETURN(1); // Result sent to client
|
|
|
|
err_unlock:
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
err:
|
|
DBUG_RETURN(0); // Query was not cached
|
|
}
|
|
|
|
|
|
/*
|
|
Remove all cached queries that uses any of the tables in the list
|
|
*/
|
|
|
|
void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
|
|
my_bool using_transactions)
|
|
{
|
|
DBUG_ENTER("Query_cache::invalidate (table list)");
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0 && !flush_in_progress)
|
|
{
|
|
DUMP(this);
|
|
|
|
using_transactions= using_transactions &&
|
|
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
|
|
for (; tables_used; tables_used= tables_used->next_local)
|
|
{
|
|
DBUG_ASSERT(!using_transactions || tables_used->table!=0);
|
|
if (tables_used->derived)
|
|
continue;
|
|
if (using_transactions &&
|
|
(tables_used->table->file->table_cache_type() ==
|
|
HA_CACHE_TBL_TRANSACT))
|
|
/*
|
|
Tables_used->table can't be 0 in transaction.
|
|
Only 'drop' invalidate not opened table, but 'drop'
|
|
force transaction finish.
|
|
*/
|
|
thd->add_changed_table(tables_used->table);
|
|
else
|
|
invalidate_table(tables_used);
|
|
}
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
|
|
{
|
|
DBUG_ENTER("Query_cache::invalidate (changed table list)");
|
|
if (tables_used)
|
|
{
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0 && !flush_in_progress)
|
|
{
|
|
DUMP(this);
|
|
for (; tables_used; tables_used= tables_used->next)
|
|
{
|
|
invalidate_table((byte*) tables_used->key, tables_used->key_length);
|
|
DBUG_PRINT("qcache", ("db: %s table: %s", tables_used->key,
|
|
tables_used->key+
|
|
strlen(tables_used->key)+1));
|
|
}
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Invalidate locked for write
|
|
|
|
SYNOPSIS
|
|
Query_cache::invalidate_locked_for_write()
|
|
tables_used - table list
|
|
|
|
NOTE
|
|
can be used only for opened tables
|
|
*/
|
|
void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
|
|
{
|
|
DBUG_ENTER("Query_cache::invalidate_locked_for_write");
|
|
if (tables_used)
|
|
{
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0 && !flush_in_progress)
|
|
{
|
|
DUMP(this);
|
|
for (; tables_used; tables_used= tables_used->next_local)
|
|
{
|
|
if (tables_used->lock_type & (TL_WRITE_LOW_PRIORITY | TL_WRITE) &&
|
|
tables_used->table)
|
|
invalidate_table(tables_used->table);
|
|
}
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*
|
|
Remove all cached queries that uses the given table
|
|
*/
|
|
|
|
void Query_cache::invalidate(THD *thd, TABLE *table,
|
|
my_bool using_transactions)
|
|
{
|
|
DBUG_ENTER("Query_cache::invalidate (table)");
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0 && !flush_in_progress)
|
|
{
|
|
using_transactions= using_transactions &&
|
|
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
|
|
if (using_transactions &&
|
|
(table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
|
|
thd->add_changed_table(table);
|
|
else
|
|
invalidate_table(table);
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
|
|
my_bool using_transactions)
|
|
{
|
|
DBUG_ENTER("Query_cache::invalidate (key)");
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0 && !flush_in_progress)
|
|
{
|
|
using_transactions= using_transactions &&
|
|
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
|
|
if (using_transactions) // used for innodb => has_transactions() is TRUE
|
|
thd->add_changed_table(key, key_length);
|
|
else
|
|
invalidate_table((byte*)key, key_length);
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*
|
|
Remove all cached queries that uses the given database
|
|
*/
|
|
|
|
void Query_cache::invalidate(char *db)
|
|
{
|
|
DBUG_ENTER("Query_cache::invalidate (db)");
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0 && !flush_in_progress)
|
|
{
|
|
DUMP(this);
|
|
restart_search:
|
|
if (tables_blocks)
|
|
{
|
|
Query_cache_block *curr= tables_blocks;
|
|
Query_cache_block *next;
|
|
do
|
|
{
|
|
next= curr->next;
|
|
if (strcmp(db, (char*)(curr->table()->db())) == 0)
|
|
invalidate_table(curr);
|
|
/*
|
|
invalidate_table can freed block on which point 'next' (if
|
|
table of this block used only in queries which was deleted
|
|
by invalidate_table). As far as we do not allocate new blocks
|
|
and mark all headers of freed blocks as 'FREE' (even if they are
|
|
merged with other blocks) we can just test type of block
|
|
to be sure that block is not deleted
|
|
*/
|
|
if (next->type == Query_cache_block::FREE)
|
|
goto restart_search;
|
|
curr= next;
|
|
} while (curr != tables_blocks);
|
|
}
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
|
|
{
|
|
DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0 && !flush_in_progress)
|
|
{
|
|
/* Calculate the key outside the lock to make the lock shorter */
|
|
char key[MAX_DBKEY_LENGTH];
|
|
uint32 db_length;
|
|
uint key_length= filename_2_table_key(key, filename, &db_length);
|
|
Query_cache_block *table_block;
|
|
if ((table_block = (Query_cache_block*) hash_search(&tables,
|
|
(byte*) key,
|
|
key_length)))
|
|
invalidate_table(table_block);
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/* Remove all queries from cache */
|
|
|
|
void Query_cache::flush()
|
|
{
|
|
DBUG_ENTER("Query_cache::flush");
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (query_cache_size > 0)
|
|
{
|
|
DUMP(this);
|
|
flush_cache();
|
|
DUMP(this);
|
|
}
|
|
|
|
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/* Join result in cache in 1 block (if result length > join_limit) */
|
|
|
|
void Query_cache::pack(ulong join_limit, uint iteration_limit)
|
|
{
|
|
DBUG_ENTER("Query_cache::pack");
|
|
uint i = 0;
|
|
do
|
|
{
|
|
pack_cache();
|
|
} while ((++i < iteration_limit) && join_results(join_limit));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void Query_cache::destroy()
|
|
{
|
|
DBUG_ENTER("Query_cache::destroy");
|
|
if (!initialized)
|
|
{
|
|
DBUG_PRINT("qcache", ("Query Cache not initialized"));
|
|
}
|
|
else
|
|
{
|
|
/* Underlying code expects the lock. */
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
free_cache();
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
pthread_cond_destroy(&COND_flush_finished);
|
|
pthread_mutex_destroy(&structure_guard_mutex);
|
|
initialized = 0;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
init/destroy
|
|
*****************************************************************************/
|
|
|
|
void Query_cache::init()
|
|
{
|
|
DBUG_ENTER("Query_cache::init");
|
|
pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
|
|
pthread_cond_init(&COND_flush_finished, NULL);
|
|
flush_in_progress= FALSE;
|
|
initialized = 1;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
ulong Query_cache::init_cache()
|
|
{
|
|
uint mem_bin_count, num, step;
|
|
ulong mem_bin_size, prev_size, inc;
|
|
ulong additional_data_size, max_mem_bin_size, approx_additional_data_size;
|
|
int align;
|
|
|
|
DBUG_ENTER("Query_cache::init_cache");
|
|
approx_additional_data_size = (sizeof(Query_cache) +
|
|
sizeof(gptr)*(def_query_hash_size+
|
|
def_table_hash_size));
|
|
if (query_cache_size < approx_additional_data_size)
|
|
goto err;
|
|
|
|
query_cache_size-= approx_additional_data_size;
|
|
align= query_cache_size % ALIGN_SIZE(1);
|
|
if (align)
|
|
{
|
|
query_cache_size-= align;
|
|
approx_additional_data_size+= align;
|
|
}
|
|
|
|
/*
|
|
Count memory bins number.
|
|
Check section 6. in start comment for the used algorithm.
|
|
*/
|
|
|
|
max_mem_bin_size = query_cache_size >> QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2;
|
|
mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
|
|
QUERY_CACHE_MEM_BIN_PARTS_MUL);
|
|
mem_bin_num = 1;
|
|
mem_bin_steps = 1;
|
|
mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
|
|
prev_size = 0;
|
|
if (mem_bin_size <= min_allocation_unit)
|
|
{
|
|
DBUG_PRINT("qcache", ("too small query cache => query cache disabled"));
|
|
// TODO here (and above) should be warning in 4.1
|
|
goto err;
|
|
}
|
|
while (mem_bin_size > min_allocation_unit)
|
|
{
|
|
mem_bin_num += mem_bin_count;
|
|
prev_size = mem_bin_size;
|
|
mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
|
|
mem_bin_steps++;
|
|
mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
|
|
mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
|
|
|
|
// Prevent too small bins spacing
|
|
if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
|
|
mem_bin_count= (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
|
|
}
|
|
inc = (prev_size - mem_bin_size) / mem_bin_count;
|
|
mem_bin_num += (mem_bin_count - (min_allocation_unit - mem_bin_size)/inc);
|
|
mem_bin_steps++;
|
|
additional_data_size = ((mem_bin_num+1) *
|
|
ALIGN_SIZE(sizeof(Query_cache_memory_bin))+
|
|
(mem_bin_steps *
|
|
ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
|
|
|
|
if (query_cache_size < additional_data_size)
|
|
goto err;
|
|
query_cache_size -= additional_data_size;
|
|
|
|
if (!(cache= (byte *)
|
|
my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
|
|
goto err;
|
|
|
|
DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins",
|
|
query_cache_size, min_allocation_unit, mem_bin_num));
|
|
|
|
steps = (Query_cache_memory_bin_step *) cache;
|
|
bins = ((Query_cache_memory_bin *)
|
|
(cache + mem_bin_steps *
|
|
ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
|
|
|
|
first_block = (Query_cache_block *) (cache + additional_data_size);
|
|
first_block->init(query_cache_size);
|
|
total_blocks++;
|
|
first_block->pnext=first_block->pprev=first_block;
|
|
first_block->next=first_block->prev=first_block;
|
|
|
|
/* Prepare bins */
|
|
|
|
bins[0].init(max_mem_bin_size);
|
|
steps[0].init(max_mem_bin_size,0,0);
|
|
mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
|
|
QUERY_CACHE_MEM_BIN_PARTS_MUL);
|
|
num= step= 1;
|
|
mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
|
|
while (mem_bin_size > min_allocation_unit)
|
|
{
|
|
ulong incr = (steps[step-1].size - mem_bin_size) / mem_bin_count;
|
|
unsigned long size = mem_bin_size;
|
|
for (uint i= mem_bin_count; i > 0; i--)
|
|
{
|
|
bins[num+i-1].init(size);
|
|
size += incr;
|
|
}
|
|
num += mem_bin_count;
|
|
steps[step].init(mem_bin_size, num-1, incr);
|
|
mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
|
|
step++;
|
|
mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
|
|
mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
|
|
if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
|
|
mem_bin_count=(mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
|
|
}
|
|
inc = (steps[step-1].size - mem_bin_size) / mem_bin_count;
|
|
|
|
/*
|
|
num + mem_bin_count > mem_bin_num, but index never be > mem_bin_num
|
|
because block with size < min_allocated_unit never will be requested
|
|
*/
|
|
|
|
steps[step].init(mem_bin_size, num + mem_bin_count - 1, inc);
|
|
{
|
|
uint skiped = (min_allocation_unit - mem_bin_size)/inc;
|
|
ulong size = mem_bin_size + inc*skiped;
|
|
uint i = mem_bin_count - skiped;
|
|
while (i-- > 0)
|
|
{
|
|
bins[num+i].init(size);
|
|
size += inc;
|
|
}
|
|
}
|
|
bins[mem_bin_num].number = 1; // For easy end test in get_free_block
|
|
free_memory = free_memory_blocks = 0;
|
|
insert_into_free_memory_list(first_block);
|
|
|
|
DUMP(this);
|
|
|
|
VOID(hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0,
|
|
query_cache_query_get_key, 0, 0));
|
|
#ifndef FN_NO_CASE_SENCE
|
|
/*
|
|
If lower_case_table_names!=0 then db and table names are already
|
|
converted to lower case and we can use binary collation for their
|
|
comparison (no matter if file system case sensitive or not).
|
|
If we have case-sensitive file system (like on most Unixes) and
|
|
lower_case_table_names == 0 then we should distinguish my_table
|
|
and MY_TABLE cases and so again can use binary collation.
|
|
*/
|
|
VOID(hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0,
|
|
query_cache_table_get_key, 0, 0));
|
|
#else
|
|
/*
|
|
On windows, OS/2, MacOS X with HFS+ or any other case insensitive
|
|
file system if lower_case_table_names!=0 we have same situation as
|
|
in previous case, but if lower_case_table_names==0 then we should
|
|
not distinguish cases (to be compatible in behavior with underlying
|
|
file system) and so should use case insensitive collation for
|
|
comparison.
|
|
*/
|
|
VOID(hash_init(&tables,
|
|
lower_case_table_names ? &my_charset_bin :
|
|
files_charset_info,
|
|
def_table_hash_size, 0, 0,query_cache_table_get_key, 0, 0));
|
|
#endif
|
|
|
|
queries_in_cache = 0;
|
|
queries_blocks = 0;
|
|
DBUG_RETURN(query_cache_size +
|
|
additional_data_size + approx_additional_data_size);
|
|
|
|
err:
|
|
make_disabled();
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/* Disable the use of the query cache */
|
|
|
|
void Query_cache::make_disabled()
|
|
{
|
|
DBUG_ENTER("Query_cache::make_disabled");
|
|
query_cache_size= 0;
|
|
queries_blocks= 0;
|
|
free_memory= 0;
|
|
bins= 0;
|
|
steps= 0;
|
|
cache= 0;
|
|
mem_bin_num= mem_bin_steps= 0;
|
|
queries_in_cache= 0;
|
|
first_block= 0;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
free_cache() - free all resources allocated by the cache.
|
|
|
|
SYNOPSIS
|
|
free_cache()
|
|
|
|
DESCRIPTION
|
|
This function frees all resources allocated by the cache. You
|
|
have to call init_cache() before using the cache again.
|
|
*/
|
|
|
|
void Query_cache::free_cache()
|
|
{
|
|
DBUG_ENTER("Query_cache::free_cache");
|
|
if (query_cache_size > 0)
|
|
{
|
|
flush_cache();
|
|
#ifndef DBUG_OFF
|
|
if (bins[0].free_blocks == 0)
|
|
{
|
|
wreck(__LINE__,"no free memory found in (bins[0].free_blocks");
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
#endif
|
|
|
|
/* Becasue we did a flush, all cache memory must be in one this block */
|
|
bins[0].free_blocks->destroy();
|
|
total_blocks--;
|
|
#ifndef DBUG_OFF
|
|
if (free_memory != query_cache_size)
|
|
DBUG_PRINT("qcache", ("free memory %lu (should be %lu)",
|
|
free_memory , query_cache_size));
|
|
#endif
|
|
my_free((gptr) cache, MYF(MY_ALLOW_ZERO_PTR));
|
|
make_disabled();
|
|
hash_free(&queries);
|
|
hash_free(&tables);
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Free block data
|
|
*****************************************************************************/
|
|
|
|
|
|
/*
|
|
flush_cache() - flush the cache.
|
|
|
|
SYNOPSIS
|
|
flush_cache()
|
|
|
|
DESCRIPTION
|
|
This function will flush cache contents. It assumes we have
|
|
'structure_guard_mutex' locked. The function sets the
|
|
flush_in_progress flag and releases the lock, so other threads may
|
|
proceed skipping the cache as if it is disabled. Concurrent
|
|
flushes are performed in turn.
|
|
*/
|
|
|
|
void Query_cache::flush_cache()
|
|
{
|
|
/*
|
|
If there is flush in progress, wait for it to finish, and then do
|
|
our flush. This is necessary because something could be added to
|
|
the cache before we acquire the lock again, and some code (like
|
|
Query_cache::free_cache()) depends on the fact that after the
|
|
flush the cache is empty.
|
|
*/
|
|
while (flush_in_progress)
|
|
pthread_cond_wait(&COND_flush_finished, &structure_guard_mutex);
|
|
|
|
/*
|
|
Setting 'flush_in_progress' will prevent other threads from using
|
|
the cache while we are in the middle of the flush, and we release
|
|
the lock so that other threads won't block.
|
|
*/
|
|
flush_in_progress= TRUE;
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
|
|
my_hash_reset(&queries);
|
|
while (queries_blocks != 0)
|
|
{
|
|
BLOCK_LOCK_WR(queries_blocks);
|
|
free_query_internal(queries_blocks);
|
|
}
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
flush_in_progress= FALSE;
|
|
pthread_cond_signal(&COND_flush_finished);
|
|
}
|
|
|
|
/*
|
|
Free oldest query that is not in use by another thread.
|
|
Returns 1 if we couldn't remove anything
|
|
*/
|
|
|
|
my_bool Query_cache::free_old_query()
|
|
{
|
|
DBUG_ENTER("Query_cache::free_old_query");
|
|
if (queries_blocks)
|
|
{
|
|
/*
|
|
try_lock_writing used to prevent client because here lock
|
|
sequence is breached.
|
|
Also we don't need remove locked queries at this point.
|
|
*/
|
|
Query_cache_block *query_block = 0;
|
|
if (queries_blocks != 0)
|
|
{
|
|
Query_cache_block *block = queries_blocks;
|
|
/* Search until we find first query that we can remove */
|
|
do
|
|
{
|
|
Query_cache_query *header = block->query();
|
|
if (header->result() != 0 &&
|
|
header->result()->type == Query_cache_block::RESULT &&
|
|
block->query()->try_lock_writing())
|
|
{
|
|
query_block = block;
|
|
break;
|
|
}
|
|
} while ((block=block->next) != queries_blocks );
|
|
}
|
|
|
|
if (query_block != 0)
|
|
{
|
|
free_query(query_block);
|
|
lowmem_prunes++;
|
|
DBUG_RETURN(0);
|
|
}
|
|
}
|
|
DBUG_RETURN(1); // Nothing to remove
|
|
}
|
|
|
|
|
|
/*
|
|
free_query_internal() - free query from query cache.
|
|
|
|
SYNOPSIS
|
|
free_query_internal()
|
|
query_block Query_cache_block representing the query
|
|
|
|
DESCRIPTION
|
|
This function will remove the query from a cache, and place its
|
|
memory blocks to the list of free blocks. 'query_block' must be
|
|
locked for writing, this function will release (and destroy) this
|
|
lock.
|
|
|
|
NOTE
|
|
'query_block' should be removed from 'queries' hash _before_
|
|
calling this method, as the lock will be destroyed here.
|
|
*/
|
|
|
|
void Query_cache::free_query_internal(Query_cache_block *query_block)
|
|
{
|
|
DBUG_ENTER("Query_cache::free_query_internal");
|
|
DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
|
|
(ulong) query_block,
|
|
query_block->query()->length() ));
|
|
|
|
queries_in_cache--;
|
|
|
|
Query_cache_query *query= query_block->query();
|
|
|
|
if (query->writer() != 0)
|
|
{
|
|
/* Tell MySQL that this query should not be cached anymore */
|
|
query->writer()->query_cache_query= 0;
|
|
query->writer(0);
|
|
}
|
|
double_linked_list_exclude(query_block, &queries_blocks);
|
|
Query_cache_block_table *table= query_block->table(0);
|
|
|
|
for (TABLE_COUNTER_TYPE i= 0; i < query_block->n_tables; i++)
|
|
unlink_table(table++);
|
|
Query_cache_block *result_block= query->result();
|
|
|
|
/*
|
|
The following is true when query destruction was called and no results
|
|
in query . (query just registered and then abort/pack/flush called)
|
|
*/
|
|
if (result_block != 0)
|
|
{
|
|
if (result_block->type != Query_cache_block::RESULT)
|
|
{
|
|
// removing unfinished query
|
|
refused++;
|
|
inserts--;
|
|
}
|
|
Query_cache_block *block= result_block;
|
|
do
|
|
{
|
|
Query_cache_block *current= block;
|
|
block= block->next;
|
|
free_memory_block(current);
|
|
} while (block != result_block);
|
|
}
|
|
else
|
|
{
|
|
// removing unfinished query
|
|
refused++;
|
|
inserts--;
|
|
}
|
|
|
|
query->unlock_n_destroy();
|
|
free_memory_block(query_block);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
free_query() - free query from query cache.
|
|
|
|
SYNOPSIS
|
|
free_query()
|
|
query_block Query_cache_block representing the query
|
|
|
|
DESCRIPTION
|
|
This function will remove 'query_block' from 'queries' hash, and
|
|
then call free_query_internal(), which see.
|
|
*/
|
|
|
|
void Query_cache::free_query(Query_cache_block *query_block)
|
|
{
|
|
DBUG_ENTER("Query_cache::free_query");
|
|
DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
|
|
(ulong) query_block,
|
|
query_block->query()->length() ));
|
|
|
|
hash_delete(&queries,(byte *) query_block);
|
|
free_query_internal(query_block);
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Query data creation
|
|
*****************************************************************************/
|
|
|
|
Query_cache_block *
|
|
Query_cache::write_block_data(ulong data_len, gptr data,
|
|
ulong header_len,
|
|
Query_cache_block::block_type type,
|
|
TABLE_COUNTER_TYPE ntab,
|
|
my_bool under_guard)
|
|
{
|
|
ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
|
|
ALIGN_SIZE(ntab*sizeof(Query_cache_block_table)) +
|
|
header_len);
|
|
ulong len = data_len + all_headers_len;
|
|
ulong align_len= ALIGN_SIZE(len);
|
|
DBUG_ENTER("Query_cache::write_block_data");
|
|
DBUG_PRINT("qcache", ("data: %ld, header: %ld, all header: %ld",
|
|
data_len, header_len, all_headers_len));
|
|
Query_cache_block *block = allocate_block(max(align_len,
|
|
min_allocation_unit),
|
|
1, 0, under_guard);
|
|
if (block != 0)
|
|
{
|
|
block->type = type;
|
|
block->n_tables = ntab;
|
|
block->used = len;
|
|
|
|
memcpy((void*) (((byte *) block)+ all_headers_len),
|
|
(void*) data, data_len);
|
|
}
|
|
DBUG_RETURN(block);
|
|
}
|
|
|
|
|
|
/*
|
|
On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be done.
|
|
*/
|
|
|
|
my_bool
|
|
Query_cache::append_result_data(Query_cache_block **current_block,
|
|
ulong data_len, gptr data,
|
|
Query_cache_block *query_block)
|
|
{
|
|
DBUG_ENTER("Query_cache::append_result_data");
|
|
DBUG_PRINT("qcache", ("append %lu bytes to 0x%lx query",
|
|
data_len, (long) query_block));
|
|
|
|
if (query_block->query()->add(data_len) > query_cache_limit)
|
|
{
|
|
DBUG_PRINT("qcache", ("size limit reached %lu > %lu",
|
|
query_block->query()->length(),
|
|
query_cache_limit));
|
|
DBUG_RETURN(0);
|
|
}
|
|
if (*current_block == 0)
|
|
{
|
|
DBUG_PRINT("qcache", ("allocated first result data block %lu", data_len));
|
|
/*
|
|
STRUCT_UNLOCK(&structure_guard_mutex) Will be done by
|
|
write_result_data if success;
|
|
*/
|
|
DBUG_RETURN(write_result_data(current_block, data_len, data, query_block,
|
|
Query_cache_block::RES_BEG));
|
|
}
|
|
Query_cache_block *last_block = (*current_block)->prev;
|
|
|
|
DBUG_PRINT("qcache", ("lastblock 0x%lx len %lu used %lu",
|
|
(ulong) last_block, last_block->length,
|
|
last_block->used));
|
|
my_bool success = 1;
|
|
ulong last_block_free_space= last_block->length - last_block->used;
|
|
|
|
/*
|
|
We will first allocate and write the 'tail' of data, that doesn't fit
|
|
in the 'last_block'. Only if this succeeds, we will fill the last_block.
|
|
This saves us a memcpy if the query doesn't fit in the query cache.
|
|
*/
|
|
|
|
// Try join blocks if physically next block is free...
|
|
ulong tail = data_len - last_block_free_space;
|
|
ulong append_min = get_min_append_result_data_size();
|
|
if (last_block_free_space < data_len &&
|
|
append_next_free_block(last_block,
|
|
max(tail, append_min)))
|
|
last_block_free_space = last_block->length - last_block->used;
|
|
// If no space in last block (even after join) allocate new block
|
|
if (last_block_free_space < data_len)
|
|
{
|
|
DBUG_PRINT("qcache", ("allocate new block for %lu bytes",
|
|
data_len-last_block_free_space));
|
|
Query_cache_block *new_block = 0;
|
|
/*
|
|
On success STRUCT_UNLOCK(&structure_guard_mutex) will be done
|
|
by the next call
|
|
*/
|
|
success = write_result_data(&new_block, data_len-last_block_free_space,
|
|
(gptr)(((byte*)data)+last_block_free_space),
|
|
query_block,
|
|
Query_cache_block::RES_CONT);
|
|
/*
|
|
new_block may be != 0 even !success (if write_result_data
|
|
allocate a small block but failed to allocate continue)
|
|
*/
|
|
if (new_block != 0)
|
|
double_linked_list_join(last_block, new_block);
|
|
}
|
|
else
|
|
{
|
|
// It is success (nobody can prevent us write data)
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
}
|
|
|
|
// Now finally write data to the last block
|
|
if (success && last_block_free_space > 0)
|
|
{
|
|
ulong to_copy = min(data_len,last_block_free_space);
|
|
DBUG_PRINT("qcache", ("use free space %lub at block 0x%lx to copy %lub",
|
|
last_block_free_space, (ulong)last_block, to_copy));
|
|
memcpy((void*) (((byte*) last_block) + last_block->used), (void*) data,
|
|
to_copy);
|
|
last_block->used+=to_copy;
|
|
}
|
|
DBUG_RETURN(success);
|
|
}
|
|
|
|
|
|
my_bool Query_cache::write_result_data(Query_cache_block **result_block,
|
|
ulong data_len, gptr data,
|
|
Query_cache_block *query_block,
|
|
Query_cache_block::block_type type)
|
|
{
|
|
DBUG_ENTER("Query_cache::write_result_data");
|
|
DBUG_PRINT("qcache", ("data_len %lu",data_len));
|
|
|
|
/*
|
|
Reserve block(s) for filling
|
|
During data allocation we must have structure_guard_mutex locked.
|
|
As data copy is not a fast operation, it's better if we don't have
|
|
structure_guard_mutex locked during data coping.
|
|
Thus we first allocate space and lock query, then unlock
|
|
structure_guard_mutex and copy data.
|
|
*/
|
|
|
|
my_bool success = allocate_data_chain(result_block, data_len, query_block,
|
|
type == Query_cache_block::RES_BEG);
|
|
if (success)
|
|
{
|
|
// It is success (nobody can prevent us write data)
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
uint headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
|
|
ALIGN_SIZE(sizeof(Query_cache_result)));
|
|
#ifndef EMBEDDED_LIBRARY
|
|
Query_cache_block *block= *result_block;
|
|
byte *rest= (byte*) data;
|
|
// Now fill list of blocks that created by allocate_data_chain
|
|
do
|
|
{
|
|
block->type = type;
|
|
ulong length = block->used - headers_len;
|
|
DBUG_PRINT("qcache", ("write %lu byte in block 0x%lx",length,
|
|
(ulong)block));
|
|
memcpy((void*)(((byte*) block)+headers_len), (void*) rest, length);
|
|
rest += length;
|
|
block = block->next;
|
|
type = Query_cache_block::RES_CONT;
|
|
} while (block != *result_block);
|
|
#else
|
|
/*
|
|
Set type of first block, emb_store_querycache_result() will handle
|
|
the others.
|
|
*/
|
|
(*result_block)->type= type;
|
|
Querycache_stream qs(*result_block, headers_len);
|
|
emb_store_querycache_result(&qs, (THD*)data);
|
|
#endif /*!EMBEDDED_LIBRARY*/
|
|
}
|
|
else
|
|
{
|
|
if (*result_block != 0)
|
|
{
|
|
// Destroy list of blocks that was created & locked by lock_result_data
|
|
Query_cache_block *block = *result_block;
|
|
do
|
|
{
|
|
Query_cache_block *current = block;
|
|
block = block->next;
|
|
free_memory_block(current);
|
|
} while (block != *result_block);
|
|
*result_block = 0;
|
|
/*
|
|
It is not success => not unlock structure_guard_mutex (we need it to
|
|
free query)
|
|
*/
|
|
}
|
|
}
|
|
DBUG_PRINT("qcache", ("success %d", (int) success));
|
|
DBUG_RETURN(success);
|
|
}
|
|
|
|
inline ulong Query_cache::get_min_first_result_data_size()
|
|
{
|
|
if (queries_in_cache < QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER)
|
|
return min_result_data_size;
|
|
ulong avg_result = (query_cache_size - free_memory) / queries_in_cache;
|
|
avg_result = min(avg_result, query_cache_limit);
|
|
return max(min_result_data_size, avg_result);
|
|
}
|
|
|
|
inline ulong Query_cache::get_min_append_result_data_size()
|
|
{
|
|
return min_result_data_size;
|
|
}
|
|
|
|
/*
|
|
Allocate one or more blocks to hold data
|
|
*/
|
|
my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
|
|
ulong data_len,
|
|
Query_cache_block *query_block,
|
|
my_bool first_block_arg)
|
|
{
|
|
ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
|
|
ALIGN_SIZE(sizeof(Query_cache_result)));
|
|
ulong min_size = (first_block_arg ?
|
|
get_min_first_result_data_size():
|
|
get_min_append_result_data_size());
|
|
Query_cache_block *prev_block= NULL;
|
|
Query_cache_block *new_block;
|
|
DBUG_ENTER("Query_cache::allocate_data_chain");
|
|
DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu",
|
|
data_len, all_headers_len));
|
|
|
|
do
|
|
{
|
|
ulong len= data_len + all_headers_len;
|
|
ulong align_len= ALIGN_SIZE(len);
|
|
|
|
if (!(new_block= allocate_block(max(min_size, align_len),
|
|
min_result_data_size == 0,
|
|
all_headers_len + min_result_data_size,
|
|
1)))
|
|
{
|
|
DBUG_PRINT("warning", ("Can't allocate block for results"));
|
|
DBUG_RETURN(FALSE);
|
|
}
|
|
|
|
new_block->n_tables = 0;
|
|
new_block->used = min(len, new_block->length);
|
|
new_block->type = Query_cache_block::RES_INCOMPLETE;
|
|
new_block->next = new_block->prev = new_block;
|
|
Query_cache_result *header = new_block->result();
|
|
header->parent(query_block);
|
|
|
|
DBUG_PRINT("qcache", ("Block len %lu used %lu",
|
|
new_block->length, new_block->used));
|
|
|
|
if (prev_block)
|
|
double_linked_list_join(prev_block, new_block);
|
|
else
|
|
*result_block= new_block;
|
|
if (new_block->length >= len)
|
|
break;
|
|
|
|
/*
|
|
We got less memory then we need (no big memory blocks) =>
|
|
Continue to allocated more blocks until we got everything we need.
|
|
*/
|
|
data_len= len - new_block->length;
|
|
prev_block= new_block;
|
|
} while (1);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Tables management
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
Invalidate the first table in the table_list
|
|
*/
|
|
|
|
void Query_cache::invalidate_table(TABLE_LIST *table_list)
|
|
{
|
|
if (table_list->table != 0)
|
|
invalidate_table(table_list->table); // Table is open
|
|
else
|
|
{
|
|
char key[MAX_DBKEY_LENGTH];
|
|
uint key_length;
|
|
Query_cache_block *table_block;
|
|
key_length=(uint) (strmov(strmov(key,table_list->db)+1,
|
|
table_list->table_name) -key)+ 1;
|
|
|
|
// We don't store temporary tables => no key_length+=4 ...
|
|
if ((table_block = (Query_cache_block*)
|
|
hash_search(&tables,(byte*) key,key_length)))
|
|
invalidate_table(table_block);
|
|
}
|
|
}
|
|
|
|
void Query_cache::invalidate_table(TABLE *table)
|
|
{
|
|
invalidate_table((byte*) table->s->table_cache_key.str,
|
|
table->s->table_cache_key.length);
|
|
}
|
|
|
|
void Query_cache::invalidate_table(byte * key, uint32 key_length)
|
|
{
|
|
Query_cache_block *table_block;
|
|
if ((table_block = ((Query_cache_block*)
|
|
hash_search(&tables, key, key_length))))
|
|
invalidate_table(table_block);
|
|
}
|
|
|
|
void Query_cache::invalidate_table(Query_cache_block *table_block)
|
|
{
|
|
Query_cache_block_table *list_root = table_block->table(0);
|
|
while (list_root->next != list_root)
|
|
{
|
|
Query_cache_block *query_block = list_root->next->block();
|
|
BLOCK_LOCK_WR(query_block);
|
|
free_query(query_block);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Register given table list begining with given position in tables table of
|
|
block
|
|
|
|
SYNOPSIS
|
|
Query_cache::register_tables_from_list
|
|
tables_used given table list
|
|
counter number current position in table of tables of block
|
|
block_table pointer to current position in tables table of block
|
|
|
|
RETURN
|
|
0 error
|
|
number of next position of table entry in table of tables of block
|
|
*/
|
|
|
|
TABLE_COUNTER_TYPE
|
|
Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
|
|
TABLE_COUNTER_TYPE counter,
|
|
Query_cache_block_table *block_table)
|
|
{
|
|
TABLE_COUNTER_TYPE n;
|
|
DBUG_ENTER("Query_cache::register_tables_from_list");
|
|
for (n= counter;
|
|
tables_used;
|
|
tables_used= tables_used->next_global, n++, block_table++)
|
|
{
|
|
if (tables_used->derived && !tables_used->view)
|
|
{
|
|
DBUG_PRINT("qcache", ("derived table skipped"));
|
|
n--;
|
|
block_table--;
|
|
continue;
|
|
}
|
|
block_table->n= n;
|
|
if (tables_used->view)
|
|
{
|
|
char key[MAX_DBKEY_LENGTH];
|
|
uint key_length;
|
|
DBUG_PRINT("qcache", ("view: %s db: %s",
|
|
tables_used->view_name.str,
|
|
tables_used->view_db.str));
|
|
key_length= (uint) (strmov(strmov(key, tables_used->view_db.str) + 1,
|
|
tables_used->view_name.str) - key) + 1;
|
|
/*
|
|
There are not callback function for for VIEWs
|
|
*/
|
|
if (!insert_table(key_length, key, block_table,
|
|
tables_used->view_db.length + 1,
|
|
HA_CACHE_TBL_NONTRANSACT, 0, 0))
|
|
DBUG_RETURN(0);
|
|
/*
|
|
We do not need to register view tables here because they are already
|
|
present in the global list.
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("table: %s db: %s openinfo: 0x%lx keylen: %u key: 0x%lx",
|
|
tables_used->table->s->table_name.str,
|
|
tables_used->table->s->table_cache_key.str,
|
|
(ulong) tables_used->table,
|
|
tables_used->table->s->table_cache_key.length,
|
|
(ulong) tables_used->table->s->table_cache_key.str));
|
|
if (!insert_table(tables_used->table->s->table_cache_key.length,
|
|
tables_used->table->s->table_cache_key.str,
|
|
block_table,
|
|
tables_used->db_length,
|
|
tables_used->table->file->table_cache_type(),
|
|
tables_used->callback_func,
|
|
tables_used->engine_data))
|
|
DBUG_RETURN(0);
|
|
|
|
if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM)
|
|
{
|
|
ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
|
|
MYRG_INFO *file = handler->myrg_info();
|
|
for (MYRG_TABLE *table = file->open_tables;
|
|
table != file->end_table ;
|
|
table++)
|
|
{
|
|
char key[MAX_DBKEY_LENGTH];
|
|
uint32 db_length;
|
|
uint key_length= filename_2_table_key(key, table->table->filename,
|
|
&db_length);
|
|
(++block_table)->n= ++n;
|
|
/*
|
|
There are not callback function for for MyISAM, and engine data
|
|
*/
|
|
if (!insert_table(key_length, key, block_table,
|
|
db_length,
|
|
tables_used->table->file->table_cache_type(),
|
|
0, 0))
|
|
DBUG_RETURN(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DBUG_RETURN(n - counter);
|
|
}
|
|
|
|
/*
|
|
Store all used tables
|
|
|
|
SYNOPSIS
|
|
register_all_tables()
|
|
block Store tables in this block
|
|
tables_used List if used tables
|
|
tables_arg Not used ?
|
|
*/
|
|
|
|
my_bool Query_cache::register_all_tables(Query_cache_block *block,
|
|
TABLE_LIST *tables_used,
|
|
TABLE_COUNTER_TYPE tables_arg)
|
|
{
|
|
TABLE_COUNTER_TYPE n;
|
|
DBUG_PRINT("qcache", ("register tables block 0x%lx, n %d, header %x",
|
|
(ulong) block, (int) tables_arg,
|
|
(int) ALIGN_SIZE(sizeof(Query_cache_block))));
|
|
|
|
Query_cache_block_table *block_table = block->table(0);
|
|
|
|
n= register_tables_from_list(tables_used, 0, block_table);
|
|
|
|
if (n)
|
|
{
|
|
DBUG_PRINT("qcache", ("failed at table %d", (int) n));
|
|
/* Unlink the tables we allocated above */
|
|
for (Query_cache_block_table *tmp = block->table(0) ;
|
|
tmp != block_table;
|
|
tmp++)
|
|
unlink_table(tmp);
|
|
}
|
|
return (n);
|
|
}
|
|
|
|
/*
|
|
Insert used tablename in cache
|
|
Returns 0 on error
|
|
*/
|
|
|
|
my_bool
|
|
Query_cache::insert_table(uint key_len, char *key,
|
|
Query_cache_block_table *node,
|
|
uint32 db_length, uint8 cache_type,
|
|
qc_engine_callback callback,
|
|
ulonglong engine_data)
|
|
{
|
|
DBUG_ENTER("Query_cache::insert_table");
|
|
DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
|
|
(ulong)node, key_len));
|
|
|
|
Query_cache_block *table_block = ((Query_cache_block *)
|
|
hash_search(&tables, (byte*) key,
|
|
key_len));
|
|
|
|
if (table_block &&
|
|
table_block->table()->engine_data() != engine_data)
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("Handler require invalidation queries of %s.%s %lu-%lu",
|
|
table_block->table()->db(),
|
|
table_block->table()->table(),
|
|
(ulong) engine_data,
|
|
(ulong) table_block->table()->engine_data()));
|
|
/*
|
|
as far as we delete all queries with this table, table block will be
|
|
deleted, too
|
|
*/
|
|
invalidate_table(table_block);
|
|
table_block= 0;
|
|
}
|
|
|
|
if (table_block == 0)
|
|
{
|
|
DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)",
|
|
(ulong) key, (int) key_len));
|
|
table_block = write_block_data(key_len, (gptr) key,
|
|
ALIGN_SIZE(sizeof(Query_cache_table)),
|
|
Query_cache_block::TABLE,
|
|
1, 1);
|
|
if (table_block == 0)
|
|
{
|
|
DBUG_PRINT("qcache", ("Can't write table name to cache"));
|
|
DBUG_RETURN(0);
|
|
}
|
|
Query_cache_table *header = table_block->table();
|
|
double_linked_list_simple_include(table_block,
|
|
&tables_blocks);
|
|
Query_cache_block_table *list_root = table_block->table(0);
|
|
list_root->n = 0;
|
|
list_root->next = list_root->prev = list_root;
|
|
if (my_hash_insert(&tables, (const byte *) table_block))
|
|
{
|
|
DBUG_PRINT("qcache", ("Can't insert table to hash"));
|
|
// write_block_data return locked block
|
|
free_memory_block(table_block);
|
|
DBUG_RETURN(0);
|
|
}
|
|
char *db = header->db();
|
|
header->table(db + db_length + 1);
|
|
header->key_length(key_len);
|
|
header->type(cache_type);
|
|
header->callback(callback);
|
|
header->engine_data(engine_data);
|
|
}
|
|
|
|
Query_cache_block_table *list_root = table_block->table(0);
|
|
node->next = list_root->next;
|
|
list_root->next = node;
|
|
node->next->prev = node;
|
|
node->prev = list_root;
|
|
node->parent = table_block->table();
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
|
|
void Query_cache::unlink_table(Query_cache_block_table *node)
|
|
{
|
|
DBUG_ENTER("Query_cache::unlink_table");
|
|
node->prev->next = node->next;
|
|
node->next->prev = node->prev;
|
|
Query_cache_block_table *neighbour = node->next;
|
|
if (neighbour->next == neighbour)
|
|
{
|
|
// list is empty (neighbor is root of list)
|
|
Query_cache_block *table_block = neighbour->block();
|
|
double_linked_list_exclude(table_block,
|
|
&tables_blocks);
|
|
hash_delete(&tables,(byte *) table_block);
|
|
free_memory_block(table_block);
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Free memory management
|
|
*****************************************************************************/
|
|
|
|
Query_cache_block *
|
|
Query_cache::allocate_block(ulong len, my_bool not_less, ulong min,
|
|
my_bool under_guard)
|
|
{
|
|
DBUG_ENTER("Query_cache::allocate_block");
|
|
DBUG_PRINT("qcache", ("len %lu, not less %d, min %lu, uder_guard %d",
|
|
len, not_less,min,under_guard));
|
|
|
|
if (len >= min(query_cache_size, query_cache_limit))
|
|
{
|
|
DBUG_PRINT("qcache", ("Query cache hase only %lu memory and limit %lu",
|
|
query_cache_size, query_cache_limit));
|
|
DBUG_RETURN(0); // in any case we don't have such piece of memory
|
|
}
|
|
|
|
if (!under_guard)
|
|
{
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
|
|
if (unlikely(query_cache.query_cache_size == 0 || flush_in_progress))
|
|
{
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_RETURN(0);
|
|
}
|
|
}
|
|
|
|
/* Free old queries until we have enough memory to store this block */
|
|
Query_cache_block *block;
|
|
do
|
|
{
|
|
block= get_free_block(len, not_less, min);
|
|
}
|
|
while (block == 0 && !free_old_query());
|
|
|
|
if (block != 0) // If we found a suitable block
|
|
{
|
|
if (block->length >= ALIGN_SIZE(len) + min_allocation_unit)
|
|
split_block(block,ALIGN_SIZE(len));
|
|
}
|
|
|
|
if (!under_guard)
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_RETURN(block);
|
|
}
|
|
|
|
|
|
Query_cache_block *
|
|
Query_cache::get_free_block(ulong len, my_bool not_less, ulong min)
|
|
{
|
|
Query_cache_block *block = 0, *first = 0;
|
|
DBUG_ENTER("Query_cache::get_free_block");
|
|
DBUG_PRINT("qcache",("length %lu, not_less %d, min %lu", len,
|
|
(int)not_less, min));
|
|
|
|
/* Find block with minimal size > len */
|
|
uint start = find_bin(len);
|
|
// try matching bin
|
|
if (bins[start].number != 0)
|
|
{
|
|
Query_cache_block *list = bins[start].free_blocks;
|
|
if (list->prev->length >= len) // check block with max size
|
|
{
|
|
first = list;
|
|
uint n = 0;
|
|
while ( n < QUERY_CACHE_MEM_BIN_TRY &&
|
|
first->length < len) //we don't need irst->next != list
|
|
{
|
|
first=first->next;
|
|
n++;
|
|
}
|
|
if (first->length >= len)
|
|
block=first;
|
|
else // we don't need if (first->next != list)
|
|
{
|
|
n = 0;
|
|
block = list->prev;
|
|
while (n < QUERY_CACHE_MEM_BIN_TRY &&
|
|
block->length > len)
|
|
{
|
|
block=block->prev;
|
|
n++;
|
|
}
|
|
if (block->length < len)
|
|
block=block->next;
|
|
}
|
|
}
|
|
else
|
|
first = list->prev;
|
|
}
|
|
if (block == 0 && start > 0)
|
|
{
|
|
DBUG_PRINT("qcache",("Try bins with bigger block size"));
|
|
// Try more big bins
|
|
int i = start - 1;
|
|
while (i > 0 && bins[i].number == 0)
|
|
i--;
|
|
if (bins[i].number > 0)
|
|
block = bins[i].free_blocks;
|
|
}
|
|
|
|
// If no big blocks => try less size (if it is possible)
|
|
if (block == 0 && ! not_less)
|
|
{
|
|
DBUG_PRINT("qcache",("Try to allocate a smaller block"));
|
|
if (first != 0 && first->length > min)
|
|
block = first;
|
|
else
|
|
{
|
|
uint i = start + 1;
|
|
/* bins[mem_bin_num].number contains 1 for easy end test */
|
|
for (i= start+1 ; bins[i].number == 0 ; i++) ;
|
|
if (i < mem_bin_num && bins[i].free_blocks->prev->length >= min)
|
|
block = bins[i].free_blocks->prev;
|
|
}
|
|
}
|
|
if (block != 0)
|
|
exclude_from_free_memory_list(block);
|
|
|
|
DBUG_PRINT("qcache",("getting block 0x%lx", (ulong) block));
|
|
DBUG_RETURN(block);
|
|
}
|
|
|
|
|
|
void Query_cache::free_memory_block(Query_cache_block *block)
|
|
{
|
|
DBUG_ENTER("Query_cache::free_memory_block");
|
|
block->used=0;
|
|
block->type= Query_cache_block::FREE; // mark block as free in any case
|
|
DBUG_PRINT("qcache",
|
|
("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
|
|
(ulong) first_block, (ulong) block, (ulong) block->pnext,
|
|
(ulong) block->pprev));
|
|
|
|
if (block->pnext != first_block && block->pnext->is_free())
|
|
block = join_free_blocks(block, block->pnext);
|
|
if (block != first_block && block->pprev->is_free())
|
|
block = join_free_blocks(block->pprev, block->pprev);
|
|
insert_into_free_memory_list(block);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void Query_cache::split_block(Query_cache_block *block, ulong len)
|
|
{
|
|
DBUG_ENTER("Query_cache::split_block");
|
|
Query_cache_block *new_block = (Query_cache_block*)(((byte*) block)+len);
|
|
|
|
new_block->init(block->length - len);
|
|
total_blocks++;
|
|
block->length=len;
|
|
new_block->pnext = block->pnext;
|
|
block->pnext = new_block;
|
|
new_block->pprev = block;
|
|
new_block->pnext->pprev = new_block;
|
|
|
|
if (block->type == Query_cache_block::FREE)
|
|
{
|
|
// if block was free then it already joined with all free neighbours
|
|
insert_into_free_memory_list(new_block);
|
|
}
|
|
else
|
|
free_memory_block(new_block);
|
|
|
|
DBUG_PRINT("qcache", ("split 0x%lx (%lu) new 0x%lx",
|
|
(ulong) block, len, (ulong) new_block));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
Query_cache_block *
|
|
Query_cache::join_free_blocks(Query_cache_block *first_block_arg,
|
|
Query_cache_block *block_in_list)
|
|
{
|
|
Query_cache_block *second_block;
|
|
DBUG_ENTER("Query_cache::join_free_blocks");
|
|
DBUG_PRINT("qcache",
|
|
("join first 0x%lx, pnext 0x%lx, in list 0x%lx",
|
|
(ulong) first_block_arg, (ulong) first_block_arg->pnext,
|
|
(ulong) block_in_list));
|
|
|
|
exclude_from_free_memory_list(block_in_list);
|
|
second_block = first_block_arg->pnext;
|
|
// May be was not free block
|
|
second_block->used=0;
|
|
second_block->destroy();
|
|
total_blocks--;
|
|
|
|
first_block_arg->length += second_block->length;
|
|
first_block_arg->pnext = second_block->pnext;
|
|
second_block->pnext->pprev = first_block_arg;
|
|
|
|
DBUG_RETURN(first_block_arg);
|
|
}
|
|
|
|
|
|
my_bool Query_cache::append_next_free_block(Query_cache_block *block,
|
|
ulong add_size)
|
|
{
|
|
Query_cache_block *next_block = block->pnext;
|
|
DBUG_ENTER("Query_cache::append_next_free_block");
|
|
DBUG_PRINT("enter", ("block 0x%lx, add_size %lu", (ulong) block,
|
|
add_size));
|
|
|
|
if (next_block != first_block && next_block->is_free())
|
|
{
|
|
ulong old_len = block->length;
|
|
exclude_from_free_memory_list(next_block);
|
|
next_block->destroy();
|
|
total_blocks--;
|
|
|
|
block->length += next_block->length;
|
|
block->pnext = next_block->pnext;
|
|
next_block->pnext->pprev = block;
|
|
|
|
if (block->length > ALIGN_SIZE(old_len + add_size) + min_allocation_unit)
|
|
split_block(block,ALIGN_SIZE(old_len + add_size));
|
|
DBUG_PRINT("exit", ("block was appended"));
|
|
DBUG_RETURN(1);
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
void Query_cache::exclude_from_free_memory_list(Query_cache_block *free_block)
|
|
{
|
|
DBUG_ENTER("Query_cache::exclude_from_free_memory_list");
|
|
Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
|
|
free_block->data());
|
|
double_linked_list_exclude(free_block, &bin->free_blocks);
|
|
bin->number--;
|
|
free_memory-=free_block->length;
|
|
free_memory_blocks--;
|
|
DBUG_PRINT("qcache",("exclude block 0x%lx, bin 0x%lx", (ulong) free_block,
|
|
(ulong) bin));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void Query_cache::insert_into_free_memory_list(Query_cache_block *free_block)
|
|
{
|
|
DBUG_ENTER("Query_cache::insert_into_free_memory_list");
|
|
uint idx = find_bin(free_block->length);
|
|
insert_into_free_memory_sorted_list(free_block, &bins[idx].free_blocks);
|
|
/*
|
|
We have enough memory in block for storing bin reference due to
|
|
min_allocation_unit choice
|
|
*/
|
|
Query_cache_memory_bin **bin_ptr = ((Query_cache_memory_bin**)
|
|
free_block->data());
|
|
*bin_ptr = bins+idx;
|
|
(*bin_ptr)->number++;
|
|
DBUG_PRINT("qcache",("insert block 0x%lx, bin[%d] 0x%lx",
|
|
(ulong) free_block, idx, (ulong) *bin_ptr));
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
uint Query_cache::find_bin(ulong size)
|
|
{
|
|
DBUG_ENTER("Query_cache::find_bin");
|
|
// Binary search
|
|
int left = 0, right = mem_bin_steps;
|
|
do
|
|
{
|
|
int middle = (left + right) / 2;
|
|
if (steps[middle].size > size)
|
|
left = middle+1;
|
|
else
|
|
right = middle;
|
|
} while (left < right);
|
|
if (left == 0)
|
|
{
|
|
// first bin not subordinate of common rules
|
|
DBUG_PRINT("qcache", ("first bin (# 0), size %lu",size));
|
|
DBUG_RETURN(0);
|
|
}
|
|
uint bin = steps[left].idx -
|
|
(uint)((size - steps[left].size)/steps[left].increment);
|
|
#ifndef DBUG_OFF
|
|
bins_dump();
|
|
#endif
|
|
DBUG_PRINT("qcache", ("bin %u step %u, size %lu step size %lu",
|
|
bin, left, size, steps[left].size));
|
|
DBUG_RETURN(bin);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Lists management
|
|
*****************************************************************************/
|
|
|
|
void Query_cache::move_to_query_list_end(Query_cache_block *query_block)
|
|
{
|
|
DBUG_ENTER("Query_cache::move_to_query_list_end");
|
|
double_linked_list_exclude(query_block, &queries_blocks);
|
|
double_linked_list_simple_include(query_block, &queries_blocks);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void Query_cache::insert_into_free_memory_sorted_list(Query_cache_block *
|
|
new_block,
|
|
Query_cache_block **
|
|
list)
|
|
{
|
|
DBUG_ENTER("Query_cache::insert_into_free_memory_sorted_list");
|
|
/*
|
|
list sorted by size in ascendant order, because we need small blocks
|
|
more frequently than bigger ones
|
|
*/
|
|
|
|
new_block->used = 0;
|
|
new_block->n_tables = 0;
|
|
new_block->type = Query_cache_block::FREE;
|
|
|
|
if (*list == 0)
|
|
{
|
|
*list = new_block->next=new_block->prev=new_block;
|
|
DBUG_PRINT("qcache", ("inserted into empty list"));
|
|
}
|
|
else
|
|
{
|
|
Query_cache_block *point = *list;
|
|
if (point->length >= new_block->length)
|
|
{
|
|
point = point->prev;
|
|
*list = new_block;
|
|
}
|
|
else
|
|
{
|
|
/* Find right position in sorted list to put block */
|
|
while (point->next != *list &&
|
|
point->next->length < new_block->length)
|
|
point=point->next;
|
|
}
|
|
new_block->prev = point;
|
|
new_block->next = point->next;
|
|
new_block->next->prev = new_block;
|
|
point->next = new_block;
|
|
}
|
|
free_memory+=new_block->length;
|
|
free_memory_blocks++;
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void
|
|
Query_cache::double_linked_list_simple_include(Query_cache_block *point,
|
|
Query_cache_block **
|
|
list_pointer)
|
|
{
|
|
DBUG_ENTER("Query_cache::double_linked_list_simple_include");
|
|
DBUG_PRINT("qcache", ("including block 0x%lx", (ulong) point));
|
|
if (*list_pointer == 0)
|
|
*list_pointer=point->next=point->prev=point;
|
|
else
|
|
{
|
|
// insert to the end of list
|
|
point->next = (*list_pointer);
|
|
point->prev = (*list_pointer)->prev;
|
|
point->prev->next = point;
|
|
(*list_pointer)->prev = point;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
void
|
|
Query_cache::double_linked_list_exclude(Query_cache_block *point,
|
|
Query_cache_block **list_pointer)
|
|
{
|
|
DBUG_ENTER("Query_cache::double_linked_list_exclude");
|
|
DBUG_PRINT("qcache", ("excluding block 0x%lx, list 0x%lx",
|
|
(ulong) point, (ulong) list_pointer));
|
|
if (point->next == point)
|
|
*list_pointer = 0; // empty list
|
|
else
|
|
{
|
|
point->next->prev = point->prev;
|
|
point->prev->next = point->next;
|
|
if (point == *list_pointer)
|
|
*list_pointer = point->next;
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
|
|
Query_cache_block *tail_head)
|
|
{
|
|
Query_cache_block *head_head = head_tail->next,
|
|
*tail_tail = tail_head->prev;
|
|
head_head->prev = tail_tail;
|
|
head_tail->next = tail_head;
|
|
tail_head->prev = head_tail;
|
|
tail_tail->next = head_head;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Query
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
Collect information about table types, check that tables are cachable and
|
|
count them
|
|
|
|
SYNOPSIS
|
|
process_and_count_tables()
|
|
tables_used table list for processing
|
|
tables_type pointer to variable for table types collection
|
|
|
|
RETURN
|
|
0 error
|
|
>0 number of tables
|
|
*/
|
|
|
|
static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
|
|
uint8 *tables_type)
|
|
{
|
|
DBUG_ENTER("process_and_count_tables");
|
|
TABLE_COUNTER_TYPE table_count = 0;
|
|
for (; tables_used; tables_used= tables_used->next_global)
|
|
{
|
|
table_count++;
|
|
if (tables_used->view)
|
|
{
|
|
DBUG_PRINT("qcache", ("view: %s db: %s",
|
|
tables_used->view_name.str,
|
|
tables_used->view_db.str));
|
|
*tables_type|= HA_CACHE_TBL_NONTRANSACT;
|
|
}
|
|
else
|
|
{
|
|
DBUG_PRINT("qcache", ("table: %s db: %s type: %u",
|
|
tables_used->table->s->table_name.str,
|
|
tables_used->table->s->db.str,
|
|
tables_used->table->s->db_type->db_type));
|
|
if (tables_used->derived)
|
|
{
|
|
table_count--;
|
|
DBUG_PRINT("qcache", ("derived table skipped"));
|
|
continue;
|
|
}
|
|
*tables_type|= tables_used->table->file->table_cache_type();
|
|
|
|
/*
|
|
table_alias_charset used here because it depends of
|
|
lower_case_table_names variable
|
|
*/
|
|
if (tables_used->table->s->tmp_table != NO_TMP_TABLE ||
|
|
(*tables_type & HA_CACHE_TBL_NOCACHE) ||
|
|
(tables_used->db_length == 5 &&
|
|
my_strnncoll(table_alias_charset,
|
|
(uchar*)tables_used->table->s->table_cache_key.str, 6,
|
|
(uchar*)"mysql",6) == 0))
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("select not cacheable: temporary, system or "
|
|
"other non-cacheable table(s)"));
|
|
DBUG_RETURN(0);
|
|
}
|
|
if (tables_used->table->s->db_type->db_type == DB_TYPE_MRG_MYISAM)
|
|
{
|
|
ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
|
|
MYRG_INFO *file = handler->myrg_info();
|
|
table_count+= (file->end_table - file->open_tables);
|
|
}
|
|
}
|
|
}
|
|
DBUG_RETURN(table_count);
|
|
}
|
|
|
|
|
|
/*
|
|
If query is cacheable return number tables in query
|
|
(query without tables are not cached)
|
|
*/
|
|
|
|
TABLE_COUNTER_TYPE
|
|
Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
|
|
TABLE_LIST *tables_used, uint8 *tables_type)
|
|
{
|
|
TABLE_COUNTER_TYPE table_count;
|
|
DBUG_ENTER("Query_cache::is_cacheable");
|
|
|
|
if (lex->sql_command == SQLCOM_SELECT &&
|
|
(thd->variables.query_cache_type == 1 ||
|
|
(thd->variables.query_cache_type == 2 && (lex->select_lex.options &
|
|
OPTION_TO_QUERY_CACHE))) &&
|
|
lex->safe_to_cache_query)
|
|
{
|
|
DBUG_PRINT("qcache", ("options: %lx %lx type: %u",
|
|
(long) OPTION_TO_QUERY_CACHE,
|
|
(long) lex->select_lex.options,
|
|
(int) thd->variables.query_cache_type));
|
|
|
|
if (!(table_count= process_and_count_tables(tables_used, tables_type)))
|
|
DBUG_RETURN(0);
|
|
|
|
if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
|
|
((*tables_type)&HA_CACHE_TBL_TRANSACT))
|
|
{
|
|
DBUG_PRINT("qcache", ("not in autocommin mode"));
|
|
DBUG_RETURN(0);
|
|
}
|
|
DBUG_PRINT("qcache", ("select is using %d tables", table_count));
|
|
DBUG_RETURN(table_count);
|
|
}
|
|
|
|
DBUG_PRINT("qcache",
|
|
("not interesting query: %d or not cacheable, options %lx %lx type: %u",
|
|
(int) lex->sql_command,
|
|
(long) OPTION_TO_QUERY_CACHE,
|
|
(long) lex->select_lex.options,
|
|
(int) thd->variables.query_cache_type));
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*
|
|
Check handler allowance to cache query with these tables
|
|
|
|
SYNOPSYS
|
|
Query_cache::ask_handler_allowance()
|
|
thd - thread handlers
|
|
tables_used - tables list used in query
|
|
|
|
RETURN
|
|
0 - caching allowed
|
|
1 - caching disallowed
|
|
*/
|
|
my_bool Query_cache::ask_handler_allowance(THD *thd,
|
|
TABLE_LIST *tables_used)
|
|
{
|
|
DBUG_ENTER("Query_cache::ask_handler_allowance");
|
|
|
|
for (; tables_used; tables_used= tables_used->next_global)
|
|
{
|
|
TABLE *table;
|
|
handler *handler;
|
|
if (!(table= tables_used->table))
|
|
continue;
|
|
handler= table->file;
|
|
if (!handler->register_query_cache_table(thd,
|
|
table->s->table_cache_key.str,
|
|
table->s->table_cache_key.length,
|
|
&tables_used->callback_func,
|
|
&tables_used->engine_data))
|
|
{
|
|
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
|
|
tables_used->db, tables_used->alias));
|
|
thd->lex->safe_to_cache_query= 0; // Don't try to cache this
|
|
DBUG_RETURN(1);
|
|
}
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
Packing
|
|
*****************************************************************************/
|
|
|
|
void Query_cache::pack_cache()
|
|
{
|
|
DBUG_ENTER("Query_cache::pack_cache");
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
|
|
if (unlikely(query_cache_size == 0 || flush_in_progress))
|
|
{
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
|
|
|
byte *border = 0;
|
|
Query_cache_block *before = 0;
|
|
ulong gap = 0;
|
|
my_bool ok = 1;
|
|
Query_cache_block *block = first_block;
|
|
DUMP(this);
|
|
|
|
if (first_block)
|
|
{
|
|
do
|
|
{
|
|
Query_cache_block *next=block->pnext;
|
|
ok = move_by_type(&border, &before, &gap, block);
|
|
block = next;
|
|
} while (ok && block != first_block);
|
|
|
|
if (border != 0)
|
|
{
|
|
Query_cache_block *new_block = (Query_cache_block *) border;
|
|
new_block->init(gap);
|
|
total_blocks++;
|
|
new_block->pnext = before->pnext;
|
|
before->pnext = new_block;
|
|
new_block->pprev = before;
|
|
new_block->pnext->pprev = new_block;
|
|
insert_into_free_memory_list(new_block);
|
|
}
|
|
DUMP(this);
|
|
}
|
|
|
|
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
my_bool Query_cache::move_by_type(byte **border,
|
|
Query_cache_block **before, ulong *gap,
|
|
Query_cache_block *block)
|
|
{
|
|
DBUG_ENTER("Query_cache::move_by_type");
|
|
|
|
my_bool ok = 1;
|
|
switch (block->type) {
|
|
case Query_cache_block::FREE:
|
|
{
|
|
DBUG_PRINT("qcache", ("block 0x%lx FREE", (ulong) block));
|
|
if (*border == 0)
|
|
{
|
|
*border = (byte *) block;
|
|
*before = block->pprev;
|
|
DBUG_PRINT("qcache", ("gap beginning here"));
|
|
}
|
|
exclude_from_free_memory_list(block);
|
|
*gap +=block->length;
|
|
block->pprev->pnext=block->pnext;
|
|
block->pnext->pprev=block->pprev;
|
|
block->destroy();
|
|
total_blocks--;
|
|
DBUG_PRINT("qcache", ("added to gap (%lu)", *gap));
|
|
break;
|
|
}
|
|
case Query_cache_block::TABLE:
|
|
{
|
|
HASH_SEARCH_STATE record_idx;
|
|
DBUG_PRINT("qcache", ("block 0x%lx TABLE", (ulong) block));
|
|
if (*border == 0)
|
|
break;
|
|
ulong len = block->length, used = block->used;
|
|
Query_cache_block_table *list_root = block->table(0);
|
|
Query_cache_block_table *tprev = list_root->prev,
|
|
*tnext = list_root->next;
|
|
Query_cache_block *prev = block->prev,
|
|
*next = block->next,
|
|
*pprev = block->pprev,
|
|
*pnext = block->pnext,
|
|
*new_block =(Query_cache_block *) *border;
|
|
uint tablename_offset = block->table()->table() - block->table()->db();
|
|
char *data = (char*) block->data();
|
|
byte *key;
|
|
uint key_length;
|
|
key=query_cache_table_get_key((byte*) block, &key_length, 0);
|
|
hash_first(&tables, (byte*) key, key_length, &record_idx);
|
|
|
|
block->destroy();
|
|
new_block->init(len);
|
|
new_block->type=Query_cache_block::TABLE;
|
|
new_block->used=used;
|
|
new_block->n_tables=1;
|
|
memmove((char*) new_block->data(), data, len-new_block->headers_len());
|
|
relink(block, new_block, next, prev, pnext, pprev);
|
|
if (tables_blocks == block)
|
|
tables_blocks = new_block;
|
|
|
|
Query_cache_block_table *nlist_root = new_block->table(0);
|
|
nlist_root->n = 0;
|
|
nlist_root->next = tnext;
|
|
tnext->prev = nlist_root;
|
|
nlist_root->prev = tprev;
|
|
tprev->next = nlist_root;
|
|
DBUG_PRINT("qcache",
|
|
("list_root: 0x%lx tnext 0x%lx tprev 0x%lx tprev->next 0x%lx tnext->prev 0x%lx",
|
|
(ulong) list_root, (ulong) tnext, (ulong) tprev,
|
|
(ulong)tprev->next, (ulong)tnext->prev));
|
|
/*
|
|
Go through all queries that uses this table and change them to
|
|
point to the new table object
|
|
*/
|
|
Query_cache_table *new_block_table=new_block->table();
|
|
for (;tnext != nlist_root; tnext=tnext->next)
|
|
tnext->parent= new_block_table;
|
|
*border += len;
|
|
*before = new_block;
|
|
/* Fix pointer to table name */
|
|
new_block->table()->table(new_block->table()->db() + tablename_offset);
|
|
/* Fix hash to point at moved block */
|
|
hash_replace(&tables, &record_idx, (byte*) new_block);
|
|
|
|
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
|
|
len, (ulong) new_block, (ulong) *border));
|
|
break;
|
|
}
|
|
case Query_cache_block::QUERY:
|
|
{
|
|
HASH_SEARCH_STATE record_idx;
|
|
DBUG_PRINT("qcache", ("block 0x%lx QUERY", (ulong) block));
|
|
if (*border == 0)
|
|
break;
|
|
BLOCK_LOCK_WR(block);
|
|
ulong len = block->length, used = block->used;
|
|
TABLE_COUNTER_TYPE n_tables = block->n_tables;
|
|
Query_cache_block *prev = block->prev,
|
|
*next = block->next,
|
|
*pprev = block->pprev,
|
|
*pnext = block->pnext,
|
|
*new_block =(Query_cache_block*) *border;
|
|
char *data = (char*) block->data();
|
|
Query_cache_block *first_result_block = ((Query_cache_query *)
|
|
block->data())->result();
|
|
byte *key;
|
|
uint key_length;
|
|
key=query_cache_query_get_key((byte*) block, &key_length, 0);
|
|
hash_first(&queries, (byte*) key, key_length, &record_idx);
|
|
// Move table of used tables
|
|
memmove((char*) new_block->table(0), (char*) block->table(0),
|
|
ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
|
|
block->query()->unlock_n_destroy();
|
|
block->destroy();
|
|
new_block->init(len);
|
|
new_block->type=Query_cache_block::QUERY;
|
|
new_block->used=used;
|
|
new_block->n_tables=n_tables;
|
|
memmove((char*) new_block->data(), data, len - new_block->headers_len());
|
|
relink(block, new_block, next, prev, pnext, pprev);
|
|
if (queries_blocks == block)
|
|
queries_blocks = new_block;
|
|
Query_cache_block_table *beg_of_table_table= block->table(0),
|
|
*end_of_table_table= block->table(n_tables);
|
|
byte *beg_of_new_table_table= (byte*) new_block->table(0);
|
|
|
|
for (TABLE_COUNTER_TYPE j=0; j < n_tables; j++)
|
|
{
|
|
Query_cache_block_table *block_table = new_block->table(j);
|
|
|
|
// use aligment from begining of table if 'next' is in same block
|
|
if ((beg_of_table_table <= block_table->next) &&
|
|
(block_table->next < end_of_table_table))
|
|
((Query_cache_block_table *)(beg_of_new_table_table +
|
|
(((byte*)block_table->next) -
|
|
((byte*)beg_of_table_table))))->prev=
|
|
block_table;
|
|
else
|
|
block_table->next->prev= block_table;
|
|
|
|
// use aligment from begining of table if 'prev' is in same block
|
|
if ((beg_of_table_table <= block_table->prev) &&
|
|
(block_table->prev < end_of_table_table))
|
|
((Query_cache_block_table *)(beg_of_new_table_table +
|
|
(((byte*)block_table->prev) -
|
|
((byte*)beg_of_table_table))))->next=
|
|
block_table;
|
|
else
|
|
block_table->prev->next = block_table;
|
|
}
|
|
DBUG_PRINT("qcache", ("after circle tt"));
|
|
*border += len;
|
|
*before = new_block;
|
|
new_block->query()->result(first_result_block);
|
|
if (first_result_block != 0)
|
|
{
|
|
Query_cache_block *result_block = first_result_block;
|
|
do
|
|
{
|
|
result_block->result()->parent(new_block);
|
|
result_block = result_block->next;
|
|
} while ( result_block != first_result_block );
|
|
}
|
|
Query_cache_query *new_query= ((Query_cache_query *) new_block->data());
|
|
my_rwlock_init(&new_query->lock, NULL);
|
|
|
|
/*
|
|
If someone is writing to this block, inform the writer that the block
|
|
has been moved.
|
|
*/
|
|
NET *net = new_block->query()->writer();
|
|
if (net != 0)
|
|
{
|
|
net->query_cache_query= (gptr) new_block;
|
|
}
|
|
/* Fix hash to point at moved block */
|
|
hash_replace(&queries, &record_idx, (byte*) new_block);
|
|
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
|
|
len, (ulong) new_block, (ulong) *border));
|
|
break;
|
|
}
|
|
case Query_cache_block::RES_INCOMPLETE:
|
|
case Query_cache_block::RES_BEG:
|
|
case Query_cache_block::RES_CONT:
|
|
case Query_cache_block::RESULT:
|
|
{
|
|
DBUG_PRINT("qcache", ("block 0x%lx RES* (%d)", (ulong) block,
|
|
(int) block->type));
|
|
if (*border == 0)
|
|
break;
|
|
Query_cache_block *query_block = block->result()->parent(),
|
|
*next = block->next,
|
|
*prev = block->prev;
|
|
Query_cache_block::block_type type = block->type;
|
|
BLOCK_LOCK_WR(query_block);
|
|
ulong len = block->length, used = block->used;
|
|
Query_cache_block *pprev = block->pprev,
|
|
*pnext = block->pnext,
|
|
*new_block =(Query_cache_block*) *border;
|
|
char *data = (char*) block->data();
|
|
block->destroy();
|
|
new_block->init(len);
|
|
new_block->type=type;
|
|
new_block->used=used;
|
|
memmove((char*) new_block->data(), data, len - new_block->headers_len());
|
|
relink(block, new_block, next, prev, pnext, pprev);
|
|
new_block->result()->parent(query_block);
|
|
Query_cache_query *query = query_block->query();
|
|
if (query->result() == block)
|
|
query->result(new_block);
|
|
*border += len;
|
|
*before = new_block;
|
|
/* If result writing complete && we have free space in block */
|
|
ulong free_space= new_block->length - new_block->used;
|
|
free_space-= free_space % ALIGN_SIZE(1);
|
|
if (query->result()->type == Query_cache_block::RESULT &&
|
|
new_block->length > new_block->used &&
|
|
*gap + free_space > min_allocation_unit &&
|
|
new_block->length - free_space > min_allocation_unit)
|
|
{
|
|
*border-= free_space;
|
|
*gap+= free_space;
|
|
DBUG_PRINT("qcache",
|
|
("rest of result free space added to gap (%lu)", *gap));
|
|
new_block->length -= free_space;
|
|
}
|
|
BLOCK_UNLOCK_WR(query_block);
|
|
DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
|
|
len, (ulong) new_block, (ulong) *border));
|
|
break;
|
|
}
|
|
default:
|
|
DBUG_PRINT("error", ("unexpected block type %d, block 0x%lx",
|
|
(int)block->type, (ulong) block));
|
|
ok = 0;
|
|
}
|
|
DBUG_RETURN(ok);
|
|
}
|
|
|
|
|
|
void Query_cache::relink(Query_cache_block *oblock,
|
|
Query_cache_block *nblock,
|
|
Query_cache_block *next, Query_cache_block *prev,
|
|
Query_cache_block *pnext, Query_cache_block *pprev)
|
|
{
|
|
if (prev == oblock) //check pointer to himself
|
|
{
|
|
nblock->prev = nblock;
|
|
nblock->next = nblock;
|
|
}
|
|
else
|
|
{
|
|
nblock->prev = prev;
|
|
prev->next=nblock;
|
|
}
|
|
if (next != oblock)
|
|
{
|
|
nblock->next = next;
|
|
next->prev=nblock;
|
|
}
|
|
nblock->pprev = pprev; // Physical pointer to himself have only 1 free block
|
|
nblock->pnext = pnext;
|
|
pprev->pnext=nblock;
|
|
pnext->pprev=nblock;
|
|
}
|
|
|
|
|
|
my_bool Query_cache::join_results(ulong join_limit)
|
|
{
|
|
my_bool has_moving = 0;
|
|
DBUG_ENTER("Query_cache::join_results");
|
|
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
if (queries_blocks != 0 && !flush_in_progress)
|
|
{
|
|
DBUG_ASSERT(query_cache_size > 0);
|
|
Query_cache_block *block = queries_blocks;
|
|
do
|
|
{
|
|
Query_cache_query *header = block->query();
|
|
if (header->result() != 0 &&
|
|
header->result()->type == Query_cache_block::RESULT &&
|
|
header->length() > join_limit)
|
|
{
|
|
Query_cache_block *new_result_block =
|
|
get_free_block(ALIGN_SIZE(header->length()) +
|
|
ALIGN_SIZE(sizeof(Query_cache_block)) +
|
|
ALIGN_SIZE(sizeof(Query_cache_result)), 1, 0);
|
|
if (new_result_block != 0)
|
|
{
|
|
has_moving = 1;
|
|
Query_cache_block *first_result = header->result();
|
|
ulong new_len = (header->length() +
|
|
ALIGN_SIZE(sizeof(Query_cache_block)) +
|
|
ALIGN_SIZE(sizeof(Query_cache_result)));
|
|
if (new_result_block->length >
|
|
ALIGN_SIZE(new_len) + min_allocation_unit)
|
|
split_block(new_result_block, ALIGN_SIZE(new_len));
|
|
BLOCK_LOCK_WR(block);
|
|
header->result(new_result_block);
|
|
new_result_block->type = Query_cache_block::RESULT;
|
|
new_result_block->n_tables = 0;
|
|
new_result_block->used = new_len;
|
|
|
|
new_result_block->next = new_result_block->prev = new_result_block;
|
|
DBUG_PRINT("qcache", ("new block %lu/%lu (%lu)",
|
|
new_result_block->length,
|
|
new_result_block->used,
|
|
header->length()));
|
|
|
|
Query_cache_result *new_result = new_result_block->result();
|
|
new_result->parent(block);
|
|
byte *write_to = (byte*) new_result->data();
|
|
Query_cache_block *result_block = first_result;
|
|
do
|
|
{
|
|
ulong len = (result_block->used - result_block->headers_len() -
|
|
ALIGN_SIZE(sizeof(Query_cache_result)));
|
|
DBUG_PRINT("loop", ("add block %lu/%lu (%lu)",
|
|
result_block->length,
|
|
result_block->used,
|
|
len));
|
|
memcpy((char *) write_to,
|
|
(char*) result_block->result()->data(),
|
|
len);
|
|
write_to += len;
|
|
Query_cache_block *old_result_block = result_block;
|
|
result_block = result_block->next;
|
|
free_memory_block(old_result_block);
|
|
} while (result_block != first_result);
|
|
BLOCK_UNLOCK_WR(block);
|
|
}
|
|
}
|
|
block = block->next;
|
|
} while ( block != queries_blocks );
|
|
}
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_RETURN(has_moving);
|
|
}
|
|
|
|
|
|
uint Query_cache::filename_2_table_key (char *key, const char *path,
|
|
uint32 *db_length)
|
|
{
|
|
char tablename[FN_REFLEN+2], *filename, *dbname;
|
|
DBUG_ENTER("Query_cache::filename_2_table_key");
|
|
|
|
/* Safety if filename didn't have a directory name */
|
|
tablename[0]= FN_LIBCHAR;
|
|
tablename[1]= FN_LIBCHAR;
|
|
/* Convert filename to this OS's format in tablename */
|
|
fn_format(tablename + 2, path, "", "", MY_REPLACE_EXT);
|
|
filename= tablename + dirname_length(tablename + 2) + 2;
|
|
/* Find start of databasename */
|
|
for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ;
|
|
*db_length= (filename - dbname) - 1;
|
|
DBUG_PRINT("qcache", ("table '%-.*s.%s'", *db_length, dbname, filename));
|
|
|
|
DBUG_RETURN((uint) (strmov(strmake(key, dbname, *db_length) + 1,
|
|
filename) -key) + 1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Functions to be used when debugging
|
|
****************************************************************************/
|
|
|
|
#if defined(DBUG_OFF) && !defined(USE_QUERY_CACHE_INTEGRITY_CHECK)
|
|
|
|
void wreck(uint line, const char *message) { query_cache_size = 0; }
|
|
void bins_dump() {}
|
|
void cache_dump() {}
|
|
void queries_dump() {}
|
|
void tables_dump() {}
|
|
my_bool check_integrity(bool not_locked) { return 0; }
|
|
my_bool in_list(Query_cache_block * root, Query_cache_block * point,
|
|
const char *name) { return 0;}
|
|
my_bool in_blocks(Query_cache_block * point) { return 0; }
|
|
|
|
#else
|
|
|
|
|
|
/*
|
|
Debug method which switch query cache off but left content for
|
|
investigation.
|
|
|
|
SYNOPSIS
|
|
Query_cache::wreck()
|
|
line line of the wreck() call
|
|
message message for logging
|
|
*/
|
|
|
|
void Query_cache::wreck(uint line, const char *message)
|
|
{
|
|
THD *thd=current_thd;
|
|
DBUG_ENTER("Query_cache::wreck");
|
|
query_cache_size = 0;
|
|
if (*message)
|
|
DBUG_PRINT("error", (" %s", message));
|
|
DBUG_PRINT("warning", ("=================================="));
|
|
DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
|
|
DBUG_PRINT("warning", ("=================================="));
|
|
if (thd)
|
|
thd->killed= THD::KILL_CONNECTION;
|
|
cache_dump();
|
|
/* check_integrity(0); */ /* Can't call it here because of locks */
|
|
bins_dump();
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
void Query_cache::bins_dump()
|
|
{
|
|
uint i;
|
|
|
|
if (!initialized || query_cache_size == 0)
|
|
{
|
|
DBUG_PRINT("qcache", ("Query Cache not initialized"));
|
|
return;
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("mem_bin_num=%u, mem_bin_steps=%u",
|
|
mem_bin_num, mem_bin_steps));
|
|
DBUG_PRINT("qcache", ("-------------------------"));
|
|
DBUG_PRINT("qcache", (" size idx step"));
|
|
DBUG_PRINT("qcache", ("-------------------------"));
|
|
for (i=0; i < mem_bin_steps; i++)
|
|
{
|
|
DBUG_PRINT("qcache", ("%10lu %3d %10lu", steps[i].size, steps[i].idx,
|
|
steps[i].increment));
|
|
}
|
|
DBUG_PRINT("qcache", ("-------------------------"));
|
|
DBUG_PRINT("qcache", (" size num"));
|
|
DBUG_PRINT("qcache", ("-------------------------"));
|
|
for (i=0; i < mem_bin_num; i++)
|
|
{
|
|
DBUG_PRINT("qcache", ("%10lu %3d 0x%lx", bins[i].size, bins[i].number,
|
|
(ulong)&(bins[i])));
|
|
if (bins[i].free_blocks)
|
|
{
|
|
Query_cache_block *block = bins[i].free_blocks;
|
|
do{
|
|
DBUG_PRINT("qcache", ("\\-- %lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
|
|
block->length, (ulong)block,
|
|
(ulong)block->next, (ulong)block->prev,
|
|
(ulong)block->pnext, (ulong)block->pprev));
|
|
block = block->next;
|
|
} while ( block != bins[i].free_blocks );
|
|
}
|
|
}
|
|
DBUG_PRINT("qcache", ("-------------------------"));
|
|
}
|
|
|
|
|
|
void Query_cache::cache_dump()
|
|
{
|
|
if (!initialized || query_cache_size == 0)
|
|
{
|
|
DBUG_PRINT("qcache", ("Query Cache not initialized"));
|
|
return;
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("-------------------------------------"));
|
|
DBUG_PRINT("qcache", (" length used t nt"));
|
|
DBUG_PRINT("qcache", ("-------------------------------------"));
|
|
Query_cache_block *i = first_block;
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache",
|
|
("%10lu %10lu %1d %2d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
|
|
i->length, i->used, (int)i->type,
|
|
i->n_tables, (ulong)i,
|
|
(ulong)i->next, (ulong)i->prev, (ulong)i->pnext,
|
|
(ulong)i->pprev));
|
|
i = i->pnext;
|
|
} while ( i != first_block );
|
|
DBUG_PRINT("qcache", ("-------------------------------------"));
|
|
}
|
|
|
|
|
|
void Query_cache::queries_dump()
|
|
{
|
|
|
|
if (!initialized)
|
|
{
|
|
DBUG_PRINT("qcache", ("Query Cache not initialized"));
|
|
return;
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("------------------"));
|
|
DBUG_PRINT("qcache", (" QUERIES"));
|
|
DBUG_PRINT("qcache", ("------------------"));
|
|
if (queries_blocks != 0)
|
|
{
|
|
Query_cache_block *block = queries_blocks;
|
|
do
|
|
{
|
|
uint len;
|
|
char *str = (char*) query_cache_query_get_key((byte*) block, &len, 0);
|
|
len-= QUERY_CACHE_FLAGS_SIZE; // Point at flags
|
|
Query_cache_query_flags flags;
|
|
memcpy(&flags, str+len, QUERY_CACHE_FLAGS_SIZE);
|
|
str[len]= 0; // make zero ending DB name
|
|
DBUG_PRINT("qcache", ("F:%u C:%u L:%lu T:'%s' (%u) '%s' '%s'",
|
|
flags.client_long_flag,
|
|
flags.character_set_client_num,
|
|
(ulong)flags.limit,
|
|
flags.time_zone->get_name()->ptr(),
|
|
len, str, strend(str)+1));
|
|
DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block,
|
|
(ulong) block->next, (ulong) block->prev,
|
|
(ulong)block->pnext, (ulong)block->pprev));
|
|
memcpy(str + len, &flags, QUERY_CACHE_FLAGS_SIZE); // restore flags
|
|
for (TABLE_COUNTER_TYPE t= 0; t < block->n_tables; t++)
|
|
{
|
|
Query_cache_table *table= block->table(t)->parent;
|
|
DBUG_PRINT("qcache", ("-t- '%s' '%s'", table->db(), table->table()));
|
|
}
|
|
Query_cache_query *header = block->query();
|
|
if (header->result())
|
|
{
|
|
Query_cache_block *result_block = header->result();
|
|
Query_cache_block *result_beg = result_block;
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache", ("-r- %u %lu/%lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
|
|
(uint) result_block->type,
|
|
result_block->length, result_block->used,
|
|
(ulong) result_block,
|
|
(ulong) result_block->next,
|
|
(ulong) result_block->prev,
|
|
(ulong) result_block->pnext,
|
|
(ulong) result_block->pprev));
|
|
result_block = result_block->next;
|
|
} while ( result_block != result_beg );
|
|
}
|
|
} while ((block=block->next) != queries_blocks);
|
|
}
|
|
else
|
|
{
|
|
DBUG_PRINT("qcache", ("no queries in list"));
|
|
}
|
|
DBUG_PRINT("qcache", ("------------------"));
|
|
}
|
|
|
|
|
|
void Query_cache::tables_dump()
|
|
{
|
|
if (!initialized || query_cache_size == 0)
|
|
{
|
|
DBUG_PRINT("qcache", ("Query Cache not initialized"));
|
|
return;
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("--------------------"));
|
|
DBUG_PRINT("qcache", ("TABLES"));
|
|
DBUG_PRINT("qcache", ("--------------------"));
|
|
if (tables_blocks != 0)
|
|
{
|
|
Query_cache_block *table_block = tables_blocks;
|
|
do
|
|
{
|
|
Query_cache_table *table = table_block->table();
|
|
DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
|
|
table_block = table_block->next;
|
|
} while ( table_block != tables_blocks);
|
|
}
|
|
else
|
|
DBUG_PRINT("qcache", ("no tables in list"));
|
|
DBUG_PRINT("qcache", ("--------------------"));
|
|
}
|
|
|
|
|
|
my_bool Query_cache::check_integrity(bool locked)
|
|
{
|
|
my_bool result = 0;
|
|
uint i;
|
|
DBUG_ENTER("check_integrity");
|
|
|
|
if (!locked)
|
|
STRUCT_LOCK(&structure_guard_mutex);
|
|
|
|
if (unlikely(query_cache_size == 0 || flush_in_progress))
|
|
{
|
|
if (!locked)
|
|
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
|
|
|
DBUG_PRINT("qcache", ("Query Cache not initialized"));
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
if (hash_check(&queries))
|
|
{
|
|
DBUG_PRINT("error", ("queries hash is damaged"));
|
|
result = 1;
|
|
}
|
|
|
|
if (hash_check(&tables))
|
|
{
|
|
DBUG_PRINT("error", ("tables hash is damaged"));
|
|
result = 1;
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("physical address check ..."));
|
|
ulong free=0, used=0;
|
|
Query_cache_block * block = first_block;
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
|
|
(ulong) block, (uint) block->type));
|
|
// Check allignment
|
|
if ((((long)block) % (long) ALIGN_SIZE(1)) !=
|
|
(((long)first_block) % (long)ALIGN_SIZE(1)))
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx do not aligned by %d", (ulong) block,
|
|
(int) ALIGN_SIZE(1)));
|
|
result = 1;
|
|
}
|
|
// Check memory allocation
|
|
if (block->pnext == first_block) // Is it last block?
|
|
{
|
|
if (((byte*)block) + block->length !=
|
|
((byte*)first_block) + query_cache_size)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx, type %u, ended at 0x%lx, but cache ended at 0x%lx",
|
|
(ulong) block, (uint) block->type,
|
|
(ulong) (((byte*)block) + block->length),
|
|
(ulong) (((byte*)first_block) + query_cache_size)));
|
|
result = 1;
|
|
}
|
|
}
|
|
else
|
|
if (((byte*)block) + block->length != ((byte*)block->pnext))
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx, type %u, ended at 0x%lx, but next block begining at 0x%lx",
|
|
(ulong) block, (uint) block->type,
|
|
(ulong) (((byte*)block) + block->length),
|
|
(ulong) ((byte*)block->pnext)));
|
|
}
|
|
if (block->type == Query_cache_block::FREE)
|
|
free+= block->length;
|
|
else
|
|
used+= block->length;
|
|
switch(block->type) {
|
|
case Query_cache_block::FREE:
|
|
{
|
|
Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
|
|
block->data());
|
|
//is it correct pointer?
|
|
if (((byte*)bin) < ((byte*)bins) ||
|
|
((byte*)bin) >= ((byte*)first_block))
|
|
{
|
|
DBUG_PRINT("error",
|
|
("free block 0x%lx have bin pointer 0x%lx beyaond of bins array bounds [0x%lx,0x%lx]",
|
|
(ulong) block,
|
|
(ulong) bin,
|
|
(ulong) bins,
|
|
(ulong) first_block));
|
|
result = 1;
|
|
}
|
|
else
|
|
{
|
|
int idx = (((byte*)bin) - ((byte*)bins)) /
|
|
sizeof(Query_cache_memory_bin);
|
|
if (in_list(bins[idx].free_blocks, block, "free memory"))
|
|
result = 1;
|
|
}
|
|
break;
|
|
}
|
|
case Query_cache_block::TABLE:
|
|
if (in_list(tables_blocks, block, "tables"))
|
|
result = 1;
|
|
if (in_table_list(block->table(0), block->table(0), "table list root"))
|
|
result = 1;
|
|
break;
|
|
case Query_cache_block::QUERY:
|
|
{
|
|
if (in_list(queries_blocks, block, "query"))
|
|
result = 1;
|
|
for (TABLE_COUNTER_TYPE j=0; j < block->n_tables; j++)
|
|
{
|
|
Query_cache_block_table *block_table = block->table(j);
|
|
Query_cache_block_table *block_table_root =
|
|
(Query_cache_block_table *)
|
|
(((byte*)block_table->parent) -
|
|
ALIGN_SIZE(sizeof(Query_cache_block_table)));
|
|
|
|
if (in_table_list(block_table, block_table_root, "table list"))
|
|
result = 1;
|
|
}
|
|
break;
|
|
}
|
|
case Query_cache_block::RES_INCOMPLETE:
|
|
// This type of block can be not lincked yet (in multithread environment)
|
|
break;
|
|
case Query_cache_block::RES_BEG:
|
|
case Query_cache_block::RES_CONT:
|
|
case Query_cache_block::RESULT:
|
|
{
|
|
Query_cache_block * query_block = block->result()->parent();
|
|
if (((byte*)query_block) < ((byte*)first_block) ||
|
|
((byte*)query_block) >= (((byte*)first_block) + query_cache_size))
|
|
{
|
|
DBUG_PRINT("error",
|
|
("result block 0x%lx have query block pointer 0x%lx beyaond of block pool bounds [0x%lx,0x%lx]",
|
|
(ulong) block,
|
|
(ulong) query_block,
|
|
(ulong) first_block,
|
|
(ulong) (((byte*)first_block) + query_cache_size)));
|
|
result = 1;
|
|
}
|
|
else
|
|
{
|
|
BLOCK_LOCK_RD(query_block);
|
|
if (in_list(queries_blocks, query_block, "query from results"))
|
|
result = 1;
|
|
if (in_list(query_block->query()->result(), block,
|
|
"results"))
|
|
result = 1;
|
|
BLOCK_UNLOCK_RD(query_block);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
DBUG_PRINT("error", ("block 0x%lx have incorrect type %u",
|
|
(long) block, block->type));
|
|
result = 1;
|
|
}
|
|
|
|
block = block->pnext;
|
|
} while (block != first_block);
|
|
|
|
if (used + free != query_cache_size)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("used memory (%lu) + free memory (%lu) != query_cache_size (%lu)",
|
|
used, free, query_cache_size));
|
|
result = 1;
|
|
}
|
|
|
|
if (free != free_memory)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("free memory (%lu) != free_memory (%lu)",
|
|
free, free_memory));
|
|
result = 1;
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("check queries ..."));
|
|
if ((block = queries_blocks))
|
|
{
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
|
|
(ulong) block, (uint) block->type));
|
|
uint length;
|
|
byte *key = query_cache_query_get_key((byte*) block, &length, 0);
|
|
gptr val = hash_search(&queries, key, length);
|
|
if (((gptr)block) != val)
|
|
{
|
|
DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx",
|
|
(ulong) block, (ulong) val));
|
|
}
|
|
if (in_blocks(block))
|
|
result = 1;
|
|
Query_cache_block * results = block->query()->result();
|
|
if (results)
|
|
{
|
|
Query_cache_block * result_block = results;
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
|
|
(ulong) block, (uint) block->type));
|
|
if (in_blocks(result_block))
|
|
result = 1;
|
|
|
|
result_block = result_block->next;
|
|
} while (result_block != results);
|
|
}
|
|
block = block->next;
|
|
} while (block != queries_blocks);
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("check tables ..."));
|
|
if ((block = tables_blocks))
|
|
{
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
|
|
(ulong) block, (uint) block->type));
|
|
uint length;
|
|
byte *key = query_cache_table_get_key((byte*) block, &length, 0);
|
|
gptr val = hash_search(&tables, key, length);
|
|
if (((gptr)block) != val)
|
|
{
|
|
DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
|
|
(ulong) block, (ulong) val));
|
|
}
|
|
|
|
if (in_blocks(block))
|
|
result = 1;
|
|
block=block->next;
|
|
} while (block != tables_blocks);
|
|
}
|
|
|
|
DBUG_PRINT("qcache", ("check free blocks"));
|
|
for (i = 0; i < mem_bin_num; i++)
|
|
{
|
|
if ((block = bins[i].free_blocks))
|
|
{
|
|
uint count = 0;
|
|
do
|
|
{
|
|
DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
|
|
(ulong) block, (uint) block->type));
|
|
if (in_blocks(block))
|
|
result = 1;
|
|
|
|
count++;
|
|
block=block->next;
|
|
} while (block != bins[i].free_blocks);
|
|
if (count != bins[i].number)
|
|
{
|
|
DBUG_PRINT("error", ("bins[%d].number = %d, but bin have %d blocks",
|
|
i, bins[i].number, count));
|
|
result = 1;
|
|
}
|
|
}
|
|
}
|
|
DBUG_ASSERT(result == 0);
|
|
if (!locked)
|
|
STRUCT_UNLOCK(&structure_guard_mutex);
|
|
DBUG_RETURN(result);
|
|
}
|
|
|
|
|
|
my_bool Query_cache::in_blocks(Query_cache_block * point)
|
|
{
|
|
my_bool result = 0;
|
|
Query_cache_block *block = point;
|
|
//back
|
|
do
|
|
{
|
|
if (block->pprev->pnext != block)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx in physical list is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
|
|
(ulong) block, (ulong) block->pprev,
|
|
(ulong) block->pprev->pnext,
|
|
(ulong) point));
|
|
//back trace
|
|
for (; block != point; block = block->pnext)
|
|
DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
|
|
result = 1;
|
|
goto err1;
|
|
}
|
|
block = block->pprev;
|
|
} while (block != first_block && block != point);
|
|
if (block != first_block)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx (0x%lx<-->0x%lx) not owned by pysical list",
|
|
(ulong) block, (ulong) block->pprev, (ulong )block->pnext));
|
|
return 1;
|
|
}
|
|
|
|
err1:
|
|
//forward
|
|
block = point;
|
|
do
|
|
{
|
|
if (block->pnext->pprev != block)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx in physicel list is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
|
|
(ulong) block, (ulong) block->pnext,
|
|
(ulong) block->pnext->pprev,
|
|
(ulong) point));
|
|
//back trace
|
|
for (; block != point; block = block->pprev)
|
|
DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
|
|
result = 1;
|
|
goto err2;
|
|
}
|
|
block = block->pnext;
|
|
} while (block != first_block);
|
|
err2:
|
|
return result;
|
|
}
|
|
|
|
|
|
my_bool Query_cache::in_list(Query_cache_block * root,
|
|
Query_cache_block * point,
|
|
const char *name)
|
|
{
|
|
my_bool result = 0;
|
|
Query_cache_block *block = point;
|
|
//back
|
|
do
|
|
{
|
|
if (block->prev->next != block)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx in list '%s' 0x%lx is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
|
|
(ulong) block, name, (ulong) root, (ulong) block->prev,
|
|
(ulong) block->prev->next,
|
|
(ulong) point));
|
|
//back trace
|
|
for (; block != point; block = block->next)
|
|
DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
|
|
result = 1;
|
|
goto err1;
|
|
}
|
|
block = block->prev;
|
|
} while (block != root && block != point);
|
|
if (block != root)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx (0x%lx<-->0x%lx) not owned by list '%s' 0x%lx",
|
|
(ulong) block,
|
|
(ulong) block->prev, (ulong) block->next,
|
|
name, (ulong) root));
|
|
return 1;
|
|
}
|
|
err1:
|
|
// forward
|
|
block = point;
|
|
do
|
|
{
|
|
if (block->next->prev != block)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("block 0x%lx in list '%s' 0x%lx is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
|
|
(ulong) block, name, (ulong) root, (ulong) block->next,
|
|
(ulong) block->next->prev,
|
|
(ulong) point));
|
|
//back trace
|
|
for (; block != point; block = block->prev)
|
|
DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
|
|
result = 1;
|
|
goto err2;
|
|
}
|
|
block = block->next;
|
|
} while (block != root);
|
|
err2:
|
|
return result;
|
|
}
|
|
|
|
void dump_node(Query_cache_block_table * node,
|
|
const char * call, const char * descr)
|
|
{
|
|
DBUG_PRINT("qcache", ("%s: %s: node: 0x%lx", call, descr, (ulong) node));
|
|
DBUG_PRINT("qcache", ("%s: %s: node block: 0x%lx",
|
|
call, descr, (ulong) node->block()));
|
|
DBUG_PRINT("qcache", ("%s: %s: next: 0x%lx", call, descr,
|
|
(ulong) node->next));
|
|
DBUG_PRINT("qcache", ("%s: %s: prev: 0x%lx", call, descr,
|
|
(ulong) node->prev));
|
|
}
|
|
|
|
my_bool Query_cache::in_table_list(Query_cache_block_table * root,
|
|
Query_cache_block_table * point,
|
|
const char *name)
|
|
{
|
|
my_bool result = 0;
|
|
Query_cache_block_table *table = point;
|
|
dump_node(root, name, "parameter root");
|
|
//back
|
|
do
|
|
{
|
|
dump_node(table, name, "list element << ");
|
|
if (table->prev->next != table)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, prev table 0x%lx(0x%lx) refered as next to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
|
|
(ulong) table, (ulong) table->block(), name,
|
|
(ulong) root, (ulong) root->block(),
|
|
(ulong) table->prev, (ulong) table->prev->block(),
|
|
(ulong) table->prev->next,
|
|
(ulong) table->prev->next->block(),
|
|
(ulong) point, (ulong) point->block()));
|
|
//back trace
|
|
for (; table != point; table = table->next)
|
|
DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
|
|
(ulong) table, (ulong) table->block()));
|
|
result = 1;
|
|
goto err1;
|
|
}
|
|
table = table->prev;
|
|
} while (table != root && table != point);
|
|
if (table != root)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("table 0x%lx(0x%lx) (0x%lx(0x%lx)<-->0x%lx(0x%lx)) not owned by list '%s' 0x%lx(0x%lx)",
|
|
(ulong) table, (ulong) table->block(),
|
|
(ulong) table->prev, (ulong) table->prev->block(),
|
|
(ulong) table->next, (ulong) table->next->block(),
|
|
name, (ulong) root, (ulong) root->block()));
|
|
return 1;
|
|
}
|
|
err1:
|
|
// forward
|
|
table = point;
|
|
do
|
|
{
|
|
dump_node(table, name, "list element >> ");
|
|
if (table->next->prev != table)
|
|
{
|
|
DBUG_PRINT("error",
|
|
("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, next table 0x%lx(0x%lx) refered as prev to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
|
|
(ulong) table, (ulong) table->block(),
|
|
name, (ulong) root, (ulong) root->block(),
|
|
(ulong) table->next, (ulong) table->next->block(),
|
|
(ulong) table->next->prev,
|
|
(ulong) table->next->prev->block(),
|
|
(ulong) point, (ulong) point->block()));
|
|
//back trace
|
|
for (; table != point; table = table->prev)
|
|
DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
|
|
(ulong) table, (ulong) table->block()));
|
|
result = 1;
|
|
goto err2;
|
|
}
|
|
table = table->next;
|
|
} while (table != root);
|
|
err2:
|
|
return result;
|
|
}
|
|
|
|
#endif /* DBUG_OFF */
|
|
|
|
#endif /*HAVE_QUERY_CACHE*/
|