3393 Ole John Aske 2011-10-18
Resurected code which implemented the new MRR interface from branch mysql-6.0-telco-7.0.
Several fixes was required in order to make that code work as a looong time
has passed since it was originally developed:
- Addapted fix for Bug#57481:'multi range read' may fail to close completed NdbScanOperations'
- Start transactions on demand when MRR operations are created.
- Corrected bug in calculating size of MRR buffer to allocate.
- Addapted code to correctly count pruned/sorted & plain scans in MRR
- Addapted code to handle user specified partition.
SPJ has not yet been integrated into the new MRR code - instead we will (temporary)
use the default MRR impl when a join is pushed.
Old MRR code is still present as a reference. (Plan to remove that in a later push)
modified:
mysql-test/suite/ndb/r/ndb_join_pushdown.result
mysql-test/suite/ndb/r/ndb_read_multi_range.result
mysql-test/suite/ndb/t/ndb_read_multi_range.test
sql/ha_ndbcluster.cc
sql/ha_ndbcluster.h
sql/handler.cc
storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp
storage/ndb/src/ndbapi/NdbScanOperation.cpp
3392 Ole John Aske 2011-10-17 [merge]
merge of mysql-5.5-cluster -> mysql-trunk-cluster
removed:
mysql-test/suite/ndb/t/memcache_basic.test
storage/ndb/memcache/cache-src/
storage/ndb/memcache/cache-src/LICENSE
storage/ndb/memcache/cache-src/assoc.c
storage/ndb/memcache/cache-src/assoc.h
storage/ndb/memcache/cache-src/default_engine.c
storage/ndb/memcache/cache-src/default_engine.h
storage/ndb/memcache/cache-src/items.c
storage/ndb/memcache/cache-src/items.h
storage/ndb/memcache/cache-src/slabs.c
storage/ndb/memcache/cache-src/slabs.h
storage/ndb/memcache/cache-src/trace.h
added:
mysql-test/suite/ndb/include/have_ndb_rqg.inc
mysql-test/suite/ndb_big/bug37983-master.opt
mysql-test/suite/ndb_big/disabled.def
mysql-test/suite/ndb_big/rqg_spj-master.opt
mysql-test/suite/ndb_big/rqg_spj.test
mysql-test/suite/ndb_memcache/include/wait_for_reconf.inc
mysql-test/suite/ndb_memcache/r/type_numeric.result
mysql-test/suite/ndb_memcache/t/type_numeric.test
storage/ndb/include/portlib/NdbGetRUsage.h
storage/ndb/memcache/extra/
storage/ndb/memcache/extra/libevent/
storage/ndb/memcache/extra/libevent/CMakeLists.txt
storage/ndb/memcache/extra/libevent/Doxyfile
storage/ndb/memcache/extra/libevent/README
storage/ndb/memcache/extra/libevent/WIN32-Code/
storage/ndb/memcache/extra/libevent/WIN32-Code/event-config.h
storage/ndb/memcache/extra/libevent/WIN32-Code/misc.c
storage/ndb/memcache/extra/libevent/WIN32-Code/misc.h
storage/ndb/memcache/extra/libevent/WIN32-Code/tree.h
storage/ndb/memcache/extra/libevent/WIN32-Code/win32.c
storage/ndb/memcache/extra/libevent/WIN32-Prj/
storage/ndb/memcache/extra/libevent/WIN32-Prj/libevent.dsp
storage/ndb/memcache/extra/libevent/WIN32-Prj/libevent.dsw
storage/ndb/memcache/extra/libevent/WIN32-Prj/libevent.sln
storage/ndb/memcache/extra/libevent/buffer.c
storage/ndb/memcache/extra/libevent/compat/
storage/ndb/memcache/extra/libevent/compat/sys/
storage/ndb/memcache/extra/libevent/compat/sys/_time.h
storage/ndb/memcache/extra/libevent/compat/sys/queue.h
storage/ndb/memcache/extra/libevent/devpoll.c
storage/ndb/memcache/extra/libevent/epoll.c
storage/ndb/memcache/extra/libevent/epoll_sub.c
storage/ndb/memcache/extra/libevent/evbuffer.c
storage/ndb/memcache/extra/libevent/evdns.3
storage/ndb/memcache/extra/libevent/evdns.c
storage/ndb/memcache/extra/libevent/evdns.h
storage/ndb/memcache/extra/libevent/event-internal.h
storage/ndb/memcache/extra/libevent/event.3
storage/ndb/memcache/extra/libevent/event.c
storage/ndb/memcache/extra/libevent/event.h
storage/ndb/memcache/extra/libevent/event_rpcgen.py
storage/ndb/memcache/extra/libevent/event_tagging.c
storage/ndb/memcache/extra/libevent/evhttp.h
storage/ndb/memcache/extra/libevent/evport.c
storage/ndb/memcache/extra/libevent/evrpc-internal.h
storage/ndb/memcache/extra/libevent/evrpc.c
storage/ndb/memcache/extra/libevent/evrpc.h
storage/ndb/memcache/extra/libevent/evsignal.h
storage/ndb/memcache/extra/libevent/evutil.c
storage/ndb/memcache/extra/libevent/evutil.h
storage/ndb/memcache/extra/libevent/http-internal.h
storage/ndb/memcache/extra/libevent/http.c
storage/ndb/memcache/extra/libevent/kqueue.c
storage/ndb/memcache/extra/libevent/log.c
storage/ndb/memcache/extra/libevent/log.h
storage/ndb/memcache/extra/libevent/min_heap.h
storage/ndb/memcache/extra/libevent/poll.c
storage/ndb/memcache/extra/libevent/sample/
storage/ndb/memcache/extra/libevent/sample/Makefile.am
storage/ndb/memcache/extra/libevent/sample/event-test.c
storage/ndb/memcache/extra/libevent/sample/signal-test.c
storage/ndb/memcache/extra/libevent/sample/time-test.c
storage/ndb/memcache/extra/libevent/select.c
storage/ndb/memcache/extra/libevent/signal.c
storage/ndb/memcache/extra/libevent/strlcpy-internal.h
storage/ndb/memcache/extra/libevent/strlcpy.c
storage/ndb/memcache/extra/libevent/test/
storage/ndb/memcache/extra/libevent/test/Makefile.am
storage/ndb/memcache/extra/libevent/test/bench.c
storage/ndb/memcache/extra/libevent/test/regress.c
storage/ndb/memcache/extra/libevent/test/regress.gen.c
storage/ndb/memcache/extra/libevent/test/regress.gen.h
storage/ndb/memcache/extra/libevent/test/regress.h
storage/ndb/memcache/extra/libevent/test/regress.rpc
storage/ndb/memcache/extra/libevent/test/regress_dns.c
storage/ndb/memcache/extra/libevent/test/regress_http.c
storage/ndb/memcache/extra/libevent/test/regress_rpc.c
storage/ndb/memcache/extra/libevent/test/test-eof.c
storage/ndb/memcache/extra/libevent/test/test-init.c
storage/ndb/memcache/extra/libevent/test/test-time.c
storage/ndb/memcache/extra/libevent/test/test-weof.c
storage/ndb/memcache/extra/libevent/test/test.sh
storage/ndb/memcache/extra/memcached/
storage/ndb/memcache/extra/memcached/AUTHORS
storage/ndb/memcache/extra/memcached/CMakeLists.txt
storage/ndb/memcache/extra/memcached/LICENSE
storage/ndb/memcache/extra/memcached/config_static.h
storage/ndb/memcache/extra/memcached/config_tests.in
storage/ndb/memcache/extra/memcached/daemon/
storage/ndb/memcache/extra/memcached/daemon/cache.c
storage/ndb/memcache/extra/memcached/daemon/cache.h
storage/ndb/memcache/extra/memcached/daemon/daemon.c
storage/ndb/memcache/extra/memcached/daemon/hash.c
storage/ndb/memcache/extra/memcached/daemon/hash.h
storage/ndb/memcache/extra/memcached/daemon/isasl.c
storage/ndb/memcache/extra/memcached/daemon/isasl.h
storage/ndb/memcache/extra/memcached/daemon/memcached.c
storage/ndb/memcache/extra/memcached/daemon/memcached.h
storage/ndb/memcache/extra/memcached/daemon/sasl_defs.c
storage/ndb/memcache/extra/memcached/daemon/sasl_defs.h
storage/ndb/memcache/extra/memcached/daemon/solaris_priv.c
storage/ndb/memcache/extra/memcached/daemon/stats.c
storage/ndb/memcache/extra/memcached/daemon/stats.h
storage/ndb/memcache/extra/memcached/daemon/thread.c
storage/ndb/memcache/extra/memcached/daemon/topkeys.c
storage/ndb/memcache/extra/memcached/daemon/topkeys.h
storage/ndb/memcache/extra/memcached/engines/
storage/ndb/memcache/extra/memcached/engines/default_engine/
storage/ndb/memcache/extra/memcached/engines/default_engine/assoc.c
storage/ndb/memcache/extra/memcached/engines/default_engine/assoc.h
storage/ndb/memcache/extra/memcached/engines/default_engine/default_engine.c
storage/ndb/memcache/extra/memcached/engines/default_engine/default_engine.h
storage/ndb/memcache/extra/memcached/engines/default_engine/items.c
storage/ndb/memcache/extra/memcached/engines/default_engine/items.h
storage/ndb/memcache/extra/memcached/engines/default_engine/slabs.c
storage/ndb/memcache/extra/memcached/engines/default_engine/slabs.h
storage/ndb/memcache/extra/memcached/extensions/
storage/ndb/memcache/extra/memcached/extensions/daemon/
storage/ndb/memcache/extra/memcached/extensions/daemon/stdin_check.c
storage/ndb/memcache/extra/memcached/extensions/loggers/
storage/ndb/memcache/extra/memcached/extensions/loggers/blackhole_logger.c
storage/ndb/memcache/extra/memcached/extensions/loggers/eventlog_logger.c
storage/ndb/memcache/extra/memcached/extensions/loggers/syslog_logger.c
storage/ndb/memcache/extra/memcached/extensions/protocol/
storage/ndb/memcache/extra/memcached/extensions/protocol/ascii_scrub.c
storage/ndb/memcache/extra/memcached/extensions/protocol/example_protocol.c
storage/ndb/memcache/extra/memcached/extensions/protocol/fragment_rw.c
storage/ndb/memcache/extra/memcached/extensions/protocol/fragment_rw.h
storage/ndb/memcache/extra/memcached/extensions/protocol_extension.h
storage/ndb/memcache/extra/memcached/include/
storage/ndb/memcache/extra/memcached/include/memcached/
storage/ndb/memcache/extra/memcached/include/memcached/callback.h
storage/ndb/memcache/extra/memcached/include/memcached/config_parser.h
storage/ndb/memcache/extra/memcached/include/memcached/engine.h
storage/ndb/memcache/extra/memcached/include/memcached/engine_common.h
storage/ndb/memcache/extra/memcached/include/memcached/engine_testapp.h
storage/ndb/memcache/extra/memcached/include/memcached/extension.h
storage/ndb/memcache/extra/memcached/include/memcached/extension_loggers.h
storage/ndb/memcache/extra/memcached/include/memcached/genhash.h
storage/ndb/memcache/extra/memcached/include/memcached/protocol_binary.h
storage/ndb/memcache/extra/memcached/include/memcached/protocol_plugin.h
storage/ndb/memcache/extra/memcached/include/memcached/server_api.h
storage/ndb/memcache/extra/memcached/include/memcached/types.h
storage/ndb/memcache/extra/memcached/include/memcached/util.h
storage/ndb/memcache/extra/memcached/include/memcached/vbucket.h
storage/ndb/memcache/extra/memcached/include/memcached/visibility.h
storage/ndb/memcache/extra/memcached/programs/
storage/ndb/memcache/extra/memcached/programs/engine_testapp.c
storage/ndb/memcache/extra/memcached/programs/mcstat.c
storage/ndb/memcache/extra/memcached/programs/mock_server.c
storage/ndb/memcache/extra/memcached/programs/mock_server.h
storage/ndb/memcache/extra/memcached/programs/sizes.c
storage/ndb/memcache/extra/memcached/programs/testapp.c
storage/ndb/memcache/extra/memcached/programs/timedrun.c
storage/ndb/memcache/extra/memcached/t/
storage/ndb/memcache/extra/memcached/t/00-startup.t
storage/ndb/memcache/extra/memcached/t/64bit.t
storage/ndb/memcache/extra/memcached/t/binary-get.t
storage/ndb/memcache/extra/memcached/t/binary-sasl.t.in
storage/ndb/memcache/extra/memcached/t/binary.t
storage/ndb/memcache/extra/memcached/t/bogus-commands.t
storage/ndb/memcache/extra/memcached/t/cas.t
storage/ndb/memcache/extra/memcached/t/cmd_extensions.t
storage/ndb/memcache/extra/memcached/t/daemonize.t
storage/ndb/memcache/extra/memcached/t/dash-M.t
storage/ndb/memcache/extra/memcached/t/evictions.t
storage/ndb/memcache/extra/memcached/t/expirations.t
storage/ndb/memcache/extra/memcached/t/flags.t
storage/ndb/memcache/extra/memcached/t/flush-all.t
storage/ndb/memcache/extra/memcached/t/getset.t
storage/ndb/memcache/extra/memcached/t/incrdecr.t
storage/ndb/memcache/extra/memcached/t/issue_104.t
storage/ndb/memcache/extra/memcached/t/issue_108.t
storage/ndb/memcache/extra/memcached/t/issue_14.t
storage/ndb/memcache/extra/memcached/t/issue_140.t
storage/ndb/memcache/extra/memcached/t/issue_152.t
storage/ndb/memcache/extra/memcached/t/issue_163.t
storage/ndb/memcache/extra/memcached/t/issue_183.t
storage/ndb/memcache/extra/memcached/t/issue_22.t
storage/ndb/memcache/extra/memcached/t/issue_29.t
storage/ndb/memcache/extra/memcached/t/issue_3.t
storage/ndb/memcache/extra/memcached/t/issue_41.t
storage/ndb/memcache/extra/memcached/t/issue_42.t
storage/ndb/memcache/extra/memcached/t/issue_50.t
storage/ndb/memcache/extra/memcached/t/issue_61.t
storage/ndb/memcache/extra/memcached/t/issue_67.t
storage/ndb/memcache/extra/memcached/t/issue_68.t
storage/ndb/memcache/extra/memcached/t/issue_70.t
storage/ndb/memcache/extra/memcached/t/item_size_max.t
storage/ndb/memcache/extra/memcached/t/lib/
storage/ndb/memcache/extra/memcached/t/lib/MemcachedTest.pm
storage/ndb/memcache/extra/memcached/t/line-lengths.t
storage/ndb/memcache/extra/memcached/t/lru.t
storage/ndb/memcache/extra/memcached/t/maxconns.t
storage/ndb/memcache/extra/memcached/t/multiversioning.t
storage/ndb/memcache/extra/memcached/t/noreply.t
storage/ndb/memcache/extra/memcached/t/sasl/
storage/ndb/memcache/extra/memcached/t/sasl/memcached.conf
storage/ndb/memcache/extra/memcached/t/scrub.t
storage/ndb/memcache/extra/memcached/t/stats-detail.t
storage/ndb/memcache/extra/memcached/t/stats.t
storage/ndb/memcache/extra/memcached/t/stress-memcached.pl
storage/ndb/memcache/extra/memcached/t/topkeys.t
storage/ndb/memcache/extra/memcached/t/udp.t
storage/ndb/memcache/extra/memcached/t/unixsocket.t
storage/ndb/memcache/extra/memcached/t/verbosity.t
storage/ndb/memcache/extra/memcached/t/whitespace.t
storage/ndb/memcache/extra/memcached/testsuite/
storage/ndb/memcache/extra/memcached/testsuite/basic_engine_testsuite.c
storage/ndb/memcache/extra/memcached/testsuite/basic_engine_testsuite.h
storage/ndb/memcache/extra/memcached/testsuite/breakdancer/
storage/ndb/memcache/extra/memcached/testsuite/breakdancer/breakdancer.py
storage/ndb/memcache/extra/memcached/testsuite/breakdancer/engine_test.py
storage/ndb/memcache/extra/memcached/testsuite/breakdancer/suite_stubs.c
storage/ndb/memcache/extra/memcached/testsuite/breakdancer/suite_stubs.h
storage/ndb/memcache/extra/memcached/trace.h
storage/ndb/memcache/extra/memcached/utilities/
storage/ndb/memcache/extra/memcached/utilities/config_parser.c
storage/ndb/memcache/extra/memcached/utilities/engine_loader.c
storage/ndb/memcache/extra/memcached/utilities/engine_loader.h
storage/ndb/memcache/extra/memcached/utilities/extension_loggers.c
storage/ndb/memcache/extra/memcached/utilities/genhash.c
storage/ndb/memcache/extra/memcached/utilities/genhash_int.h
storage/ndb/memcache/extra/memcached/utilities/util.c
storage/ndb/memcache/extra/memcached/win32/
storage/ndb/memcache/extra/memcached/win32/Makefile.mingw
storage/ndb/memcache/extra/memcached/win32/config.sh
storage/ndb/memcache/extra/memcached/win32/defs.c
storage/ndb/memcache/extra/memcached/win32/dlfcn.c
storage/ndb/memcache/extra/memcached/win32/dlfcn.h
storage/ndb/memcache/extra/memcached/win32/sysexits.h
storage/ndb/memcache/extra/memcached/win32/win32.c
storage/ndb/memcache/extra/memcached/win32/win32.h
storage/ndb/memcache/include/ConnQueryPlanSet.h
storage/ndb/memcache/src/ConnQueryPlanSet.cc
storage/ndb/memcache/src/stub.cc
storage/ndb/src/common/portlib/NdbGetRUsage.cpp
storage/ndb/src/kernel/blocks/thrman.cpp
storage/ndb/src/kernel/blocks/thrman.hpp
storage/ndb/test/rqg/alter_engine.sproc.sql
storage/ndb/test/rqg/analyze_db.sproc.sql
storage/ndb/test/rqg/copydb.sproc.sql
storage/ndb/test/rqg/load_and_run.sh
storage/ndb/test/rqg/load_rqg.sh
storage/ndb/test/rqg/oj_schema_mod.sproc.sql
storage/ndb/test/rqg/oj_schema_mod_ndb.sproc.sql
storage/ndb/test/rqg/parseargs.sh
storage/ndb/test/rqg/run_rqg.sh
storage/ndb/test/run-test/conf-daily-perf.cnf
storage/ndb/test/run-test/daily-perf-tests.txt
storage/ndb/tools/ndbinfo_select_all.cpp
modified:
.bzrignore
BUILD/compile-pentium-debug-max-no-ndb
mysql-test/lib/My/Memcache.pm
mysql-test/mysql-test-run.pl
mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test
mysql-test/suite/innodb/t/disabled.def
mysql-test/suite/ndb/r/ndb_alter_table.result
mysql-test/suite/ndb/r/ndb_basic.result
mysql-test/suite/ndb/r/ndb_index_stat.result
mysql-test/suite/ndb/r/ndbinfo.result
mysql-test/suite/ndb/t/ndb_alter_table.test
mysql-test/suite/ndb_big/my.cnf
mysql-test/suite/ndb_memcache/include/datatypes_tables.inc
mysql-test/suite/ndb_memcache/include/memcached_wait_for_ready.inc
mysql-test/suite/ndb_memcache/t/reconf1.test
mysql-test/suite/ndb_memcache/t/type_char.test
mysql-test/suite/ndb_memcache/t/type_signed.test
mysql-test/suite/ndb_memcache/t/type_unsigned.test
sql/ha_ndb_index_stat.cc
sql/ha_ndb_index_stat.h
sql/ha_ndbcluster.cc
storage/ndb/compile-cluster
storage/ndb/include/kernel/BlockNumbers.h
storage/ndb/include/kernel/ndb_limits.h
storage/ndb/include/kernel/signaldata/SchemaTrans.hpp
storage/ndb/include/mgmapi/mgmapi_config_parameters.h
storage/ndb/include/ndb_constants.h
storage/ndb/memcache/CMakeLists.txt
storage/ndb/memcache/FindMemcached.cmake
storage/ndb/memcache/atomics.cmake
storage/ndb/memcache/include/Config_v1.h
storage/ndb/memcache/include/Configuration.h
storage/ndb/memcache/include/DataTypeHandler.h
storage/ndb/memcache/include/NdbInstance.h
storage/ndb/memcache/include/Operation.h
storage/ndb/memcache/include/QueryPlan.h
storage/ndb/memcache/include/Record.h
storage/ndb/memcache/include/Scheduler.h
storage/ndb/memcache/include/TabSeparatedValues.h
storage/ndb/memcache/include/TableSpec.h
storage/ndb/memcache/include/atomics.h
storage/ndb/memcache/include/debug.h
storage/ndb/memcache/include/ndbmemcache_config.in
storage/ndb/memcache/include/workitem.h
storage/ndb/memcache/memcached_path.pl.in
storage/ndb/memcache/sandbox.sh.in
storage/ndb/memcache/src/ClusterConnectionPool.cc
storage/ndb/memcache/src/Config_v1.cc
storage/ndb/memcache/src/Configuration.cc
storage/ndb/memcache/src/DataTypeHandler.cc
storage/ndb/memcache/src/NdbInstance.cc
storage/ndb/memcache/src/Operation.cc
storage/ndb/memcache/src/QueryPlan.cc
storage/ndb/memcache/src/Record.cc
storage/ndb/memcache/src/TabSeparatedValues.cc
storage/ndb/memcache/src/TableSpec.cc
storage/ndb/memcache/src/ndb_configuration.cc
storage/ndb/memcache/src/ndb_engine.c
storage/ndb/memcache/src/ndb_engine_private.h
storage/ndb/memcache/src/ndb_pipeline.cc
storage/ndb/memcache/src/ndb_worker.cc
storage/ndb/memcache/src/schedulers/S_sched.cc
storage/ndb/memcache/src/schedulers/S_sched.h
storage/ndb/memcache/src/schedulers/Stockholm.cc
storage/ndb/memcache/src/schedulers/Stockholm.h
storage/ndb/memcache/src/workitem.c
storage/ndb/memcache/unit/CMakeLists.txt
storage/ndb/memcache/unit/all_tests.h
storage/ndb/memcache/unit/alloc.cc
storage/ndb/memcache/unit/cas.cc
storage/ndb/memcache/unit/casbits.cc
storage/ndb/memcache/unit/connpool.cc
storage/ndb/memcache/unit/harness.cc
storage/ndb/memcache/unit/incr.cc
storage/ndb/memcache/unit/queue.cc
storage/ndb/memcache/unit/stub_logger.c
storage/ndb/memcache/unit/test_workqueue.c
storage/ndb/memcache/unit/tsv.cc
storage/ndb/src/common/debugger/BlockNames.cpp
storage/ndb/src/common/portlib/CMakeLists.txt
storage/ndb/src/common/portlib/NdbThread.c
storage/ndb/src/kernel/SimBlockList.cpp
storage/ndb/src/kernel/blocks/CMakeLists.txt
storage/ndb/src/kernel/blocks/LocalProxy.cpp
storage/ndb/src/kernel/blocks/LocalProxy.hpp
storage/ndb/src/kernel/blocks/PgmanProxy.cpp
storage/ndb/src/kernel/blocks/PgmanProxy.hpp
storage/ndb/src/kernel/blocks/cmvmi/Cmvmi.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.cpp
storage/ndb/src/kernel/blocks/dbdict/Dbdict.hpp
storage/ndb/src/kernel/blocks/dbinfo/Dbinfo.cpp
storage/ndb/src/kernel/blocks/dblqh/Dblqh.hpp
storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp
storage/ndb/src/kernel/blocks/dblqh/DblqhProxy.cpp
storage/ndb/src/kernel/blocks/dbspj/DbspjProxy.hpp
storage/ndb/src/kernel/blocks/dbtc/Dbtc.hpp
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp
storage/ndb/src/kernel/blocks/dbtc/DbtcProxy.hpp
storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp
storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupGen.cpp
storage/ndb/src/kernel/blocks/dbtux/Dbtux.hpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp
storage/ndb/src/kernel/blocks/dbtux/DbtuxScan.cpp
storage/ndb/src/kernel/blocks/record_types.hpp
storage/ndb/src/kernel/blocks/tsman.cpp
storage/ndb/src/kernel/ndbd.cpp
storage/ndb/src/kernel/vm/DLFifoList.hpp
storage/ndb/src/kernel/vm/DLHashTable.hpp
storage/ndb/src/kernel/vm/DataBuffer2.hpp
storage/ndb/src/kernel/vm/Ndbinfo.hpp
storage/ndb/src/kernel/vm/NdbinfoTables.cpp
storage/ndb/src/kernel/vm/Pool.hpp
storage/ndb/src/kernel/vm/SimulatedBlock.hpp
storage/ndb/src/kernel/vm/dummy_nonmt.cpp
storage/ndb/src/kernel/vm/mt.cpp
storage/ndb/src/kernel/vm/mt.hpp
storage/ndb/src/kernel/vm/mt_thr_config.cpp
storage/ndb/src/kernel/vm/mt_thr_config.hpp
storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp
storage/ndb/src/mgmsrv/ConfigInfo.cpp
storage/ndb/src/ndbapi/TransporterFacade.cpp
storage/ndb/src/ndbapi/ndberror.c
storage/ndb/test/include/HugoCalculator.hpp
storage/ndb/test/include/HugoOperations.hpp
storage/ndb/test/include/HugoQueryBuilder.hpp
storage/ndb/test/ndbapi/testNdbApi.cpp
storage/ndb/test/run-test/atrt.hpp
storage/ndb/test/run-test/daily-basic-tests.txt
storage/ndb/test/run-test/daily-devel-tests.txt
storage/ndb/test/run-test/files.cpp
storage/ndb/test/run-test/main.cpp
storage/ndb/test/run-test/setup.cpp
storage/ndb/test/src/HugoOperations.cpp
storage/ndb/tools/CMakeLists.txt
storage/ndb/tools/ndbinfo_sql.cpp
support-files/compiler_warnings.supp
=== modified file 'mysql-test/suite/ndb/r/ndb_join_pushdown.result'
--- a/mysql-test/suite/ndb/r/ndb_join_pushdown.result 2011-10-05 07:24:39 +0000
+++ b/mysql-test/suite/ndb/r/ndb_join_pushdown.result 2011-10-18 10:43:35 +0000
@@ -4028,15 +4028,15 @@ and new_count.counter_name <> 'LOCAL_REA
and new_count.counter_name <> 'REMOTE_READS_SENT';
counter_name new_count.val - old_count.val
CONST_PRUNED_RANGE_SCANS_RECEIVED 0
-LOCAL_RANGE_SCANS_SENT 2
+LOCAL_RANGE_SCANS_SENT 0
LOCAL_TABLE_SCANS_SENT 2
PRUNED_RANGE_SCANS_RECEIVED 0
-RANGE_SCANS_RECEIVED 2
-READS_NOT_FOUND 2
+RANGE_SCANS_RECEIVED 0
+READS_NOT_FOUND 1
READS_RECEIVED 1
REMOTE_RANGE_SCANS_SENT 0
-SCAN_BATCHES_RETURNED 4
-SCAN_ROWS_RETURNED 8
+SCAN_BATCHES_RETURNED 2
+SCAN_ROWS_RETURNED 5
TABLE_SCANS_RECEIVED 2
select 'READS_SENT', sum(new_count.val - old_count.val)
from new_count, old_count
@@ -4044,7 +4044,7 @@ where new_count.counter_name = old_count
and (new_count.counter_name = 'LOCAL_READS_SENT'
or new_count.counter_name = 'REMOTE_READS_SENT');
READS_SENT sum(new_count.val - old_count.val)
-READS_SENT 7
+READS_SENT 5
drop table old_count;
drop table new_count;
drop table t1;
@@ -4191,7 +4191,7 @@ select count(*) from t1 t1, t1 t2 where
count(*)
1
pruned_scan_count
-2
+0
explain extended select count(*) from t1 t1, t1 t2 where t1.a = 10 and (t1.b<11 or t1.b>11) and t2.a = t1.c and t2.b = t1.c;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 range PRIMARY,i2 i2 8 NULL 6 100.00 Parent of 2 pushed join@1; Using where with pushed condition: ((`test`.`t1`.`a` = 10) and ((`test`.`t1`.`b` < 11) or (`test`.`t1`.`b` > 11)))
@@ -4202,7 +4202,7 @@ select count(*) from t1 t1, t1 t2 where
count(*)
1
pruned_scan_count
-2
+1
drop table t1;
create table t2(
d int not null,
@@ -5487,21 +5487,21 @@ counter_name spj_counts_at_end.val - spj
CONST_PRUNED_RANGE_SCANS_RECEIVED 6
LOCAL_TABLE_SCANS_SENT 250
PRUNED_RANGE_SCANS_RECEIVED 25
-RANGE_SCANS_RECEIVED 733
-READS_RECEIVED 58
+RANGE_SCANS_RECEIVED 703
+READS_RECEIVED 53
TABLE_SCANS_RECEIVED 250
drop table spj_counts_at_startup;
drop table spj_counts_at_end;
scan_count_derived
1.0
pruned_scan_count
-11
+8
sorted_scan_count
-40
+34
pushed_queries_defined
401
pushed_queries_dropped
-12
+6
pushed_queries_executed
-552
+529
set ndb_join_pushdown = @save_ndb_join_pushdown;
=== modified file 'mysql-test/suite/ndb/r/ndb_read_multi_range.result'
--- a/mysql-test/suite/ndb/r/ndb_read_multi_range.result 2011-09-05 14:12:11 +0000
+++ b/mysql-test/suite/ndb/r/ndb_read_multi_range.result 2011-10-18 10:43:35 +0000
@@ -602,6 +602,7 @@ t1.a + t2.a*10 + t3.a*100 + t4.a*1000,
from
t2 as t1, t2 as t2, t2 as t3, t2 as t4
where (t1.a + t2.a*10 + t3.a*100 + t4.a*1000) < 3000;
+set optimizer_switch='block_nested_loop=off';
explain
SELECT DISTINCT STRAIGHT_JOIN t1.pk FROM
t1 LEFT JOIN t2 ON t2.a = t1.a AND t2.pk != 6;
@@ -610,4 +611,5 @@ id select_type table type possible_keys
1 SIMPLE t2 range PRIMARY PRIMARY 4 NULL 6 Using where; Distinct
SELECT DISTINCT STRAIGHT_JOIN t1.pk FROM
t1 LEFT JOIN t2 ON t2.a = t1.a AND t2.pk != 6;
+set optimizer_switch='block_nested_loop=default';
drop table t1, t2;
=== modified file 'mysql-test/suite/ndb/t/ndb_read_multi_range.test'
--- a/mysql-test/suite/ndb/t/ndb_read_multi_range.test 2011-09-05 14:12:11 +0000
+++ b/mysql-test/suite/ndb/t/ndb_read_multi_range.test 2011-10-18 10:43:35 +0000
@@ -480,6 +480,7 @@ where (t1.a + t2.a*10 + t3.a*100 + t4.a*
# when the first matching 't2.a = t1.a' is found.
# - 'LEFT JOIN' is to ensure that 'Using join buffer' is *not* used
#
+set optimizer_switch='block_nested_loop=off';
explain
SELECT DISTINCT STRAIGHT_JOIN t1.pk FROM
t1 LEFT JOIN t2 ON t2.a = t1.a AND t2.pk != 6;
@@ -489,4 +490,5 @@ SELECT DISTINCT STRAIGHT_JOIN t1.pk FROM
t1 LEFT JOIN t2 ON t2.a = t1.a AND t2.pk != 6;
--enable_result_log
+set optimizer_switch='block_nested_loop=default';
drop table t1, t2;
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2011-10-17 13:30:56 +0000
+++ b/sql/ha_ndbcluster.cc 2011-10-18 10:43:35 +0000
@@ -13261,9 +13261,6 @@ ulonglong ha_ndbcluster::table_flags(voi
HA_NULL_IN_KEY |
HA_AUTO_PART_KEY |
HA_NO_PREFIX_CHAR_KEYS |
-#ifndef NDB_WITH_NEW_MRR_INTERFACE
- HA_NEED_READ_RANGE_BUFFER |
-#endif
HA_CAN_GEOMETRY |
HA_CAN_BIT_FIELD |
HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
@@ -14509,7 +14506,912 @@ void ha_ndbcluster::check_read_before_wr
DBUG_VOID_RETURN;
}
-#ifndef NDB_WITH_NEW_MRR_INTERFACE
+#ifdef NDB_WITH_NEW_MRR_INTERFACE
+/****************************************************************************
+ * MRR interface implementation
+ ***************************************************************************/
+
+
+/**
+ We will not attempt to deal with more than this many ranges in a single
+ MRR execute().
+*/
+#define MRR_MAX_RANGES 128
+
+/*
+ Types of ranges during multi_range_read.
+
+ Code assumes that X < enum_ordered_range is a valid check for range converted
+ to key operation.
+*/
+enum multi_range_types
+{
+ enum_unique_range, /// Range converted to key operation
+ enum_empty_unique_range, /// No data found (in key operation)
+ enum_ordered_range, /// Normal ordered index scan range
+ enum_skip_range /// Empty range (eg. partition pruning)
+};
+
+/**
+ Usage of the MRR buffer is as follows:
+
+ First, N char * values, each being the custom value obtained from
+ RANGE_SEQ_IF::next() that needs to be returned from multi_range_read_next().
+ N is usually == total number of ranges, but never more than MRR_MAX_RANGES
+ (the MRR is split across several execute()s if necessary). N may be lower
+ than actual number of ranges in a single execute() in case of split for
+ other reasons.
+
+ This is followed by N variable-sized entries, each
+
+ - 1 byte of multi_range_types for this range.
+
+ - (Only) for ranges converted to key operations (enum_unique_range and
+ enum_empty_unique_range), this is followed by table_share->reclength
+ bytes of row data.
+*/
+
+/* Return the needed size of the fixed array at start of HANDLER_BUFFER. */
+static ulong
+multi_range_fixed_size(int num_ranges)
+{
+ if (num_ranges > MRR_MAX_RANGES)
+ num_ranges= MRR_MAX_RANGES;
+ return num_ranges * sizeof(char *);
+}
+
+/* Return max number of ranges so that fixed part will still fit in buffer. */
+static int
+multi_range_max_ranges(int num_ranges, ulong bufsize)
+{
+ if (num_ranges > MRR_MAX_RANGES)
+ num_ranges= MRR_MAX_RANGES;
+ if (num_ranges * sizeof(char *) > bufsize)
+ num_ranges= bufsize / sizeof(char *);
+ return num_ranges;
+}
+
+/* Return the size in HANDLER_BUFFER of a variable-sized entry. */
+static ulong
+multi_range_entry_size(my_bool use_keyop, ulong reclength)
+{
+ /* Space for type byte. */
+ ulong len= 1;
+ if (use_keyop)
+ len+= reclength;
+ return len;
+}
+
+/*
+ Return the maximum size of a variable-sized entry in HANDLER_BUFFER.
+
+ Actual size may depend on key values (whether the actual value can be
+ converted to a hash key operation or needs to be done as an ordered index
+ scan).
+*/
+static ulong
+multi_range_max_entry(NDB_INDEX_TYPE keytype, ulong reclength)
+{
+ return multi_range_entry_size(keytype != ORDERED_INDEX, reclength);
+}
+
+static uchar &
+multi_range_entry_type(uchar *p)
+{
+ return *p;
+}
+
+/* Find the start of the next entry in HANDLER_BUFFER. */
+static uchar *
+multi_range_next_entry(uchar *p, ulong reclength)
+{
+ my_bool use_keyop= multi_range_entry_type(p) < enum_ordered_range;
+ return p + multi_range_entry_size(use_keyop, reclength);
+}
+
+/* Get pointer to row data (for range converted to key operation). */
+static uchar *
+multi_range_row(uchar *p)
+{
+ DBUG_ASSERT(multi_range_entry_type(p) == enum_unique_range);
+ return p + 1;
+}
+
+/* Get and put upper layer custom char *, use memcpy() for unaligned access. */
+static char *
+multi_range_get_custom(HANDLER_BUFFER *buffer, int range_no)
+{
+ DBUG_ASSERT(range_no < MRR_MAX_RANGES);
+ return ((char **)(buffer->buffer))[range_no];
+}
+
+static void
+multi_range_put_custom(HANDLER_BUFFER *buffer, int range_no, char *custom)
+{
+ DBUG_ASSERT(range_no < MRR_MAX_RANGES);
+ ((char **)(buffer->buffer))[range_no]= custom;
+}
+
+/*
+ This is used to check if an ordered index scan is needed for a range in
+ a multi range read.
+ If a scan is not needed, we use a faster primary/unique key operation
+ instead.
+*/
+static my_bool
+read_multi_needs_scan(NDB_INDEX_TYPE cur_index_type, const KEY *key_info,
+ const KEY_MULTI_RANGE *r)
+{
+ if (cur_index_type == ORDERED_INDEX)
+ return TRUE;
+ if (cur_index_type == PRIMARY_KEY_INDEX ||
+ cur_index_type == UNIQUE_INDEX)
+ return FALSE;
+ DBUG_ASSERT(cur_index_type == PRIMARY_KEY_ORDERED_INDEX ||
+ cur_index_type == UNIQUE_ORDERED_INDEX);
+ if (r->start_key.length != key_info->key_length ||
+ r->start_key.flag != HA_READ_KEY_EXACT)
+ return TRUE; // Not exact match, need scan
+ if (cur_index_type == UNIQUE_ORDERED_INDEX &&
+ check_null_in_key(key_info, r->start_key.key,r->start_key.length))
+ return TRUE; // Can't use for NULL values
+ return FALSE;
+}
+
+/*
+ Get cost and other information about MRR scan over a known list of ranges
+
+ SYNOPSIS
+ See handler::multi_range_read_info_const.
+
+ DESCRIPTION
+ The implementation is copied from handler::multi_range_read_info_const.
+ The only difference is that NDB-MRR cannot handle blob columns or keys
+ with NULLs for unique indexes. We disable MRR for those cases.
+ As Pushed join execution has not yet been integrated into NDB-MRR,
+ we also disable MRR for those.
+
+ NOTES
+ See NOTES for handler::multi_range_read_info_const().
+*/
+
+ha_rows
+ha_ndbcluster::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges_arg, uint *bufsz,
+ uint *flags, COST_VECT *cost)
+{
+ KEY_MULTI_RANGE range;
+ range_seq_t seq_it;
+ ha_rows rows, total_rows= 0;
+ uint n_ranges=0;
+ bool null_ranges= FALSE;
+ THD *thd= current_thd;
+ NDB_INDEX_TYPE key_type= get_index_type(keyno);
+ KEY* key_info= table->key_info + keyno;
+ ulong reclength= table_share->reclength;
+ ulong total_bufsize;
+ uint save_bufsize= *bufsz;
+ DBUG_ENTER("ha_ndbcluster::multi_range_read_info_const");
+
+ total_bufsize= multi_range_fixed_size(n_ranges_arg);
+
+ seq_it= seq->init(seq_init_param, n_ranges, *flags);
+ while (!seq->next(seq_it, &range))
+ {
+ if (unlikely(thd->killed != 0))
+ DBUG_RETURN(HA_POS_ERROR);
+
+ n_ranges++;
+ key_range *min_endp= range.start_key.length? &range.start_key : NULL;
+ key_range *max_endp= range.end_key.length? &range.end_key : NULL;
+ null_ranges|= (range.range_flag & NULL_RANGE);
+ if ((range.range_flag & UNIQUE_RANGE) && !(range.range_flag & NULL_RANGE))
+ rows= 1; /* there can be at most one row */
+ else
+ {
+ if (HA_POS_ERROR == (rows= this->records_in_range(keyno, min_endp,
+ max_endp)))
+ {
+ /* Can't scan one range => can't do MRR scan at all */
+ total_rows= HA_POS_ERROR;
+ break;
+ }
+ }
+ total_rows+= rows;
+ total_bufsize+=
+ multi_range_max_entry((read_multi_needs_scan(key_type, key_info, &range) ?
+ ORDERED_INDEX :
+ UNIQUE_INDEX),
+ reclength);
+ }
+
+ if (total_rows != HA_POS_ERROR)
+ {
+ if (uses_blob_value(table->read_set) ||
+ ((get_index_type(keyno) == UNIQUE_INDEX &&
+ has_null_in_unique_index(keyno)) && null_ranges)
+ || (m_pushed_join_operation==PUSHED_ROOT &&
+ !m_disable_pushed_join))
+ {
+ /* Use default MRR implementation */
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= 0;
+ }
+ else
+ {
+ total_bufsize+= multi_range_fixed_size(total_rows);
+
+ DBUG_PRINT("info", ("MRR bufsize suggested=%u want=%lu limit=%d",
+ save_bufsize, total_bufsize,
+ (*flags & HA_MRR_LIMITS) != 0));
+
+ if (unlikely(total_bufsize > (ulong)UINT_MAX))
+ total_bufsize= (ulong)UINT_MAX;
+
+ /*
+ We'll be most efficient when we have buffer big enough to accomodate
+ all ranges. But we need at least sufficient buffer for one range to
+ do MRR at all.
+ */
+ uint entry_size= multi_range_max_entry(key_type, reclength);
+ uint min_total_size= entry_size + multi_range_fixed_size(1);
+ if (save_bufsize < min_total_size)
+ {
+ if(*flags & HA_MRR_LIMITS)
+ {
+ /* Too small buffer limit to do MRR. */
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= 0;
+ }
+ else
+ {
+ *flags&= ~HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= min_total_size;
+ }
+ }
+ else
+ {
+ *flags&= ~HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= min(save_bufsize, total_bufsize);
+ }
+ }
+ DBUG_PRINT("info", ("MRR bufsize set to %u", *bufsz));
+ cost->zero();
+ cost->avg_io_cost= 1; /* assume random seeks */
+ if ((*flags & HA_MRR_INDEX_ONLY) && total_rows > 2)
+ cost->io_count= index_only_read_time(keyno, total_rows);
+ else
+ cost->io_count= read_time(keyno, n_ranges, total_rows);
+ cost->cpu_cost= total_rows * ROW_EVALUATE_COST + 0.01;
+ }
+ DBUG_RETURN(total_rows);
+}
+
+
+/*
+ Get cost and other information about MRR scan over some sequence of ranges
+
+ SYNOPSIS
+ See handler::multi_range_read_info.
+*/
+
+ha_rows
+ha_ndbcluster::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+ uint *bufsz, uint *flags, COST_VECT *cost)
+{
+ ha_rows res;
+ uint save_bufsize= *bufsz;
+ DBUG_ENTER("ha_ndbcluster::multi_range_read_info");
+
+ res= handler::multi_range_read_info(keyno, n_ranges, keys, bufsz, flags,
+ cost);
+ NDB_INDEX_TYPE key_type= get_index_type(keyno);
+ /* Disable MRR on blob read and on NULL lookup in unique index. */
+ if (uses_blob_value(table->read_set) ||
+ ( key_type == UNIQUE_INDEX &&
+ has_null_in_unique_index(keyno) &&
+ !(*flags & HA_MRR_NO_NULL_ENDPOINTS)))
+ {
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= 0;
+ }
+ else
+ {
+ ulong reclength= table_share->reclength;
+ uint entry_size= multi_range_max_entry(key_type, reclength);
+ uint min_total_size= entry_size + multi_range_fixed_size(1);
+ DBUG_PRINT("info", ("MRR bufsize suggested=%u want=%u limit=%d",
+ save_bufsize, (keys + 1) * entry_size,
+ (*flags & HA_MRR_LIMITS) != 0));
+ if (save_bufsize < min_total_size)
+ {
+ if(*flags & HA_MRR_LIMITS)
+ {
+ /* Too small buffer limit to do MRR. */
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= 0;
+ }
+ else
+ {
+ *flags&= ~HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= min_total_size;
+ }
+ }
+ else
+ {
+ *flags&= ~HA_MRR_USE_DEFAULT_IMPL;
+ *bufsz= min(save_bufsize,
+ keys * entry_size + multi_range_fixed_size(n_ranges));
+ }
+ DBUG_PRINT("info", ("MRR bufsize set to %u", *bufsz));
+ }
+ DBUG_RETURN(res);
+}
+
+int ha_ndbcluster::multi_range_read_init(RANGE_SEQ_IF *seq_funcs,
+ void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buffer)
+{
+ int error;
+ DBUG_ENTER("ha_ndbcluster::multi_range_read_init");
+
+ /*
+ If supplied buffer is smaller than needed for just one range, we cannot do
+ multi_range_read.
+ */
+ ulong bufsize= buffer->buffer_end - buffer->buffer;
+
+ if (mode & HA_MRR_USE_DEFAULT_IMPL
+ || bufsize < multi_range_fixed_size(1) +
+ multi_range_max_entry(get_index_type(active_index),
+ table_share->reclength)
+ || m_delete_cannot_batch || m_update_cannot_batch)
+ {
+ m_disable_multi_read= TRUE;
+ DBUG_RETURN(handler::multi_range_read_init(seq_funcs, seq_init_param,
+ n_ranges, mode, buffer));
+ }
+
+ /**
+ * There may still be an open m_multi_cursor from the previous mrr access on this handler.
+ * Close it now to free up resources for this NdbScanOperation.
+ */
+ if (unlikely((error= close_scan())))
+ DBUG_RETURN(error);
+
+ m_disable_multi_read= FALSE;
+
+ mrr_is_output_sorted= test(mode & HA_MRR_SORTED);
+ /*
+ Copy arguments into member variables
+ */
+ multi_range_buffer= buffer;
+ mrr_funcs= *seq_funcs;
+ mrr_iter= mrr_funcs.init(seq_init_param, n_ranges, mode);
+ ranges_in_seq= n_ranges;
+ m_range_res= mrr_funcs.next(mrr_iter, &mrr_cur_range);
+ mrr_need_range_assoc = !test(mode & HA_MRR_NO_ASSOCIATION);
+ if (mrr_need_range_assoc)
+ {
+ ha_statistic_increment(&SSV::ha_multi_range_read_init_count);
+ }
+
+ /*
+ We do not start fetching here with execute(), rather we defer this to the
+ first call to multi_range_read_next() by setting first_running_range and
+ first_unstarted_range like this.
+
+ The reason is that the MRR interface is designed so that in some cases
+ multi_range_read_next() may never get called (eg. in case of WHERE
+ condition on previous table that is never satisfied). So we may not need
+ to fetch anything.
+
+ Also, at the time of writing, returning an error from
+ multi_range_read_init() does not correctly set the error status, so we get
+ an assert on missing result status in net_end_statement().
+ */
+ first_running_range= 0;
+ first_unstarted_range= 0;
+
+ DBUG_RETURN(0);
+}
+
+
+int ha_ndbcluster::multi_range_start_retrievals(uint starting_range)
+{
+ KEY* key_info= table->key_info + active_index;
+ ulong reclength= table_share->reclength;
+ const NdbOperation* op;
+ NDB_INDEX_TYPE cur_index_type= get_index_type(active_index);
+ const NdbOperation *oplist[MRR_MAX_RANGES];
+ uint num_keyops= 0;
+ NdbTransaction *trans= m_thd_ndb->trans;
+ int error;
+
+ DBUG_ENTER("multi_range_start_retrievals");
+
+ /*
+ * read multi range will read ranges as follows (if not ordered)
+ *
+ * input read order
+ * ====== ==========
+ * pk-op 1 pk-op 1
+ * pk-op 2 pk-op 2
+ * range 3 range (3,5) NOTE result rows will be intermixed
+ * pk-op 4 pk-op 4
+ * range 5
+ * pk-op 6 pk-op 6
+ */
+
+ /*
+ We loop over all ranges, converting into primary/unique key operations if
+ possible, and adding ranges to an ordered index scan for the rest.
+
+ If the supplied HANDLER_BUFFER is too small, we may also need to do only
+ part of the multi read at once.
+ */
+
+ DBUG_ASSERT(cur_index_type != UNDEFINED_INDEX);
+ DBUG_ASSERT(m_multi_cursor==NULL);
+ DBUG_ASSERT(m_active_query==NULL);
+
+ const NdbOperation::LockMode lm = get_ndb_lock_mode(m_lock.type);
+ const uchar *end_of_buffer= multi_range_buffer->buffer_end;
+
+ /*
+ Normally we should have sufficient buffer for the whole fixed_sized part.
+ But we need to make sure we do not crash if upper layer gave us a _really_
+ small buffer.
+
+ We already checked (in multi_range_read_init()) that we got enough buffer
+ for at least one range.
+ */
+ uint min_entry_size=
+ multi_range_entry_size(!read_multi_needs_scan(cur_index_type, key_info,
+ &mrr_cur_range), reclength);
+ ulong bufsize= end_of_buffer - multi_range_buffer->buffer;
+ int max_range= multi_range_max_ranges(ranges_in_seq,
+ bufsize - min_entry_size);
+ DBUG_ASSERT(max_range > 0);
+ uchar *row_buf= multi_range_buffer->buffer + multi_range_fixed_size(max_range);
+ m_multi_range_result_ptr= row_buf;
+
+ int range_no= 0;
+ int mrr_range_no= starting_range;
+
+ for (;
+ !m_range_res;
+ range_no++, m_range_res= mrr_funcs.next(mrr_iter, &mrr_cur_range))
+ {
+ if (range_no >= max_range)
+ break;
+ my_bool need_scan=
+ read_multi_needs_scan(cur_index_type, key_info, &mrr_cur_range);
+ if (row_buf + multi_range_entry_size(!need_scan, reclength) > end_of_buffer)
+ break;
+ if (need_scan)
+ {
+ if (range_no > NdbIndexScanOperation::MaxRangeNo)
+ break;
+ /*
+ Check how much KEYINFO data we already used for index bounds, and
+ split the MRR here if it exceeds a certain limit. This way we avoid
+ overloading the TC block in the ndb kernel.
+
+ The limit used is based on the value MAX_KEY_SIZE_IN_WORDS.
+ */
+ if (m_multi_cursor && m_multi_cursor->getCurrentKeySize() >= 1000)
+ break;
+ }
+
+ mrr_range_no++;
+ multi_range_put_custom(multi_range_buffer, range_no, mrr_cur_range.ptr);
+
+ part_id_range part_spec;
+ if (m_use_partition_pruning)
+ {
+ get_partition_set(table, table->record[0], active_index,
+ &mrr_cur_range.start_key,
+ &part_spec);
+ DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u",
+ part_spec.start_part, part_spec.end_part));
+ /*
+ If partition pruning has found no partition in set
+ we can skip this scan
+ */
+ if (part_spec.start_part > part_spec.end_part)
+ {
+ /*
+ We can skip this partition since the key won't fit into any
+ partition
+ */
+ multi_range_entry_type(row_buf)= enum_skip_range;
+ row_buf= multi_range_next_entry(row_buf, reclength);
+ continue;
+ }
+ if (!trans &&
+ (part_spec.start_part == part_spec.end_part))
+ if (unlikely(!(trans= start_transaction_part_id(part_spec.start_part,
+ error))))
+ DBUG_RETURN(error);
+ }
+
+ if (need_scan)
+ {
+ if (!trans)
+ {
+ // ToDo see if we can use start_transaction_key here instead
+ if (!m_use_partition_pruning)
+ {
+ get_partition_set(table, table->record[0], active_index,
+ &mrr_cur_range.start_key,
+ &part_spec);
+ if (part_spec.start_part == part_spec.end_part)
+ {
+ if (unlikely(!(trans= start_transaction_part_id(part_spec.start_part,
+ error))))
+ DBUG_RETURN(error);
+ }
+ else if (unlikely(!(trans= start_transaction(error))))
+ DBUG_RETURN(error);
+ }
+ else if (unlikely(!(trans= start_transaction(error))))
+ DBUG_RETURN(error);
+ }
+
+ /* Create the scan operation for the first scan range. */
+ if (!m_multi_cursor)
+ {
+ /* Do a multi-range index scan for ranges not done by primary/unique key. */
+ NdbScanOperation::ScanOptions options;
+ NdbInterpretedCode code(m_table);
+
+ options.optionsPresent=
+ NdbScanOperation::ScanOptions::SO_SCANFLAGS |
+ NdbScanOperation::ScanOptions::SO_PARALLEL;
+
+ options.scan_flags=
+ NdbScanOperation::SF_ReadRangeNo |
+ NdbScanOperation::SF_MultiRange;
+
+ if (lm == NdbOperation::LM_Read)
+ options.scan_flags|= NdbScanOperation::SF_KeyInfo;
+ if (mrr_is_output_sorted)
+ options.scan_flags|= NdbScanOperation::SF_OrderByFull;
+
+ options.parallel= DEFAULT_PARALLELISM;
+
+ NdbOperation::GetValueSpec gets[2];
+ if (table_share->primary_key == MAX_KEY)
+ get_hidden_fields_scan(&options, gets);
+
+ if (m_cond && m_cond->generate_scan_filter(&code, &options))
+ ERR_RETURN(code.getNdbError());
+
+ /* Define scan */
+ NdbIndexScanOperation *scanOp= trans->scanIndex
+ (m_index[active_index].ndb_record_key,
+ m_ndb_record,
+ lm,
+ (uchar *)(table->read_set->bitmap),
+ NULL, /* All bounds specified below */
+ &options,
+ sizeof(NdbScanOperation::ScanOptions));
+
+ if (!scanOp)
+ ERR_RETURN(trans->getNdbError());
+
+ m_multi_cursor= scanOp;
+
+ /*
+ We do not get_blob_values() here, as when using blobs we always
+ fallback to non-batched multi range read (see multi_range_read_info
+ function).
+ */
+
+ /* We set m_next_row=0 to say that no row was fetched from the scan yet. */
+ m_next_row= 0;
+ }
+
+ Ndb::PartitionSpec ndbPartitionSpec;
+ const Ndb::PartitionSpec* ndbPartSpecPtr= NULL;
+
+ /* If this table uses user-defined partitioning, use MySQLD provided
+ * partition info as pruning info
+ * Otherwise, scan range pruning is performed automatically by
+ * NDBAPI based on distribution key values.
+ */
+ if (m_use_partition_pruning &&
+ m_user_defined_partitioning &&
+ (part_spec.start_part == part_spec.end_part))
+ {
+ DBUG_PRINT("info", ("Range on user-def-partitioned table can be pruned to part %u",
+ part_spec.start_part));
+ ndbPartitionSpec.type= Ndb::PartitionSpec::PS_USER_DEFINED;
+ ndbPartitionSpec.UserDefined.partitionId= part_spec.start_part;
+ ndbPartSpecPtr= &ndbPartitionSpec;
+ }
+
+ /* Include this range in the ordered index scan. */
+ NdbIndexScanOperation::IndexBound bound;
+ compute_index_bounds(bound, key_info,
+ &mrr_cur_range.start_key, &mrr_cur_range.end_key, 0);
+ bound.range_no= range_no;
+
+ if (m_multi_cursor->setBound(m_index[active_index].ndb_record_key,
+ bound,
+ ndbPartSpecPtr, // Only for user-def tables
+ sizeof(Ndb::PartitionSpec)))
+ {
+ ERR_RETURN(trans->getNdbError());
+ }
+
+ multi_range_entry_type(row_buf)= enum_ordered_range;
+ row_buf= multi_range_next_entry(row_buf, reclength);
+ }
+ else
+ {
+ if (!trans)
+ {
+ DBUG_ASSERT(active_index != MAX_KEY);
+ if (unlikely(!(trans= start_transaction_key(active_index,
+ mrr_cur_range.start_key.key,
+ error))))
+ DBUG_RETURN(error);
+ }
+ /* Convert to primary/unique key operation. */
+ Uint32 partitionId;
+ Uint32* ppartitionId = NULL;
+
+ if (m_user_defined_partitioning &&
+ (cur_index_type == PRIMARY_KEY_ORDERED_INDEX ||
+ cur_index_type == PRIMARY_KEY_INDEX))
+ {
+ partitionId=part_spec.start_part;
+ ppartitionId=&partitionId;
+ }
+
+ multi_range_entry_type(row_buf)= enum_unique_range;
+ if (!(op= pk_unique_index_read_key(active_index,
+ mrr_cur_range.start_key.key,
+ multi_range_row(row_buf), lm,
+ ppartitionId)))
+ ERR_RETURN(trans->getNdbError());
+ oplist[num_keyops++]= op;
+ row_buf= multi_range_next_entry(row_buf, reclength);
+ }
+ }
+
+ if (m_multi_cursor)
+ {
+ DBUG_PRINT("info", ("Is MRR scan pruned to 1 partition? :%u",
+ m_multi_cursor->getPruned()));
+ m_thd_ndb->m_scan_count++;
+ m_thd_ndb->m_pruned_scan_count += (m_multi_cursor->getPruned()? 1 : 0);
+ if (mrr_is_output_sorted)
+ {
+ m_thd_ndb->m_sorted_scan_count++;
+ }
+ }
+
+ if (execute_no_commit_ie(m_thd_ndb, trans))
+ ERR_RETURN(trans->getNdbError());
+
+ if (!m_range_res)
+ {
+ DBUG_PRINT("info",
+ ("Split MRR read, %d-%d of %d bufsize=%lu used=%lu range_no=%d",
+ starting_range, mrr_range_no - 1, ranges_in_seq,
+ (ulong)(end_of_buffer - multi_range_buffer->buffer),
+ (ulong)(row_buf - multi_range_buffer->buffer), range_no));
+ /*
+ Mark that we're using entire buffer (even if might not) as we are not
+ reading read all ranges yet.
+
+ This as we don't want mysqld to reuse the buffer when we read the
+ remaining ranges.
+ */
+ multi_range_buffer->end_of_used_area= multi_range_buffer->buffer_end;
+ }
+ else
+ multi_range_buffer->end_of_used_area= row_buf;
+
+ first_running_range= first_range_in_batch= starting_range;
+ first_unstarted_range= mrr_range_no;
+ m_current_range_no= 0;
+
+ /*
+ Now we need to inspect all ranges that were converted to key operations.
+
+ We need to check for any error (in particular NoDataFound), and remember
+ the status, since the operation pointer may no longer be valid when we
+ actually get to it in multi_range_next_entry() (we may have done further
+ execute()'s in a different handler object during joins eg.)
+ */
+ row_buf= m_multi_range_result_ptr;
+ uint op_idx= 0;
+ for (uint r= first_range_in_batch; r < first_unstarted_range; r++)
+ {
+ uchar &type_loc= multi_range_entry_type(row_buf);
+ row_buf= multi_range_next_entry(row_buf, reclength);
+ if (type_loc >= enum_ordered_range)
+ continue;
+
+ DBUG_ASSERT(op_idx < MRR_MAX_RANGES);
+ const NdbError &error= oplist[op_idx]->getNdbError();
+ if (error.code != 0)
+ {
+ if (error.classification == NdbError::NoDataFound)
+ type_loc= enum_empty_unique_range;
+ else
+ {
+ /*
+ This shouldn't really happen.
+
+ There aren't really any other errors that could happen on the read
+ without also aborting the transaction and causing execute() to
+ return failure.
+
+ (But we can still safely return an error code in non-debug builds).
+ */
+ DBUG_ASSERT(FALSE);
+ ERR_RETURN(error); /* purecov: deadcode */
+ }
+ }
+ op_idx++;
+ }
+
+ DBUG_RETURN(0);
+}
+
+int ha_ndbcluster::multi_range_read_next(char **range_info)
+{
+ int res;
+ DBUG_ENTER("ha_ndbcluster::multi_range_read_next");
+
+ if (m_disable_multi_read)
+ {
+ DBUG_RETURN(handler::multi_range_read_next(range_info));
+ }
+
+ for(;;)
+ {
+
+ /* for each range (we should have remembered the number) */
+ while (first_running_range < first_unstarted_range)
+ {
+ uchar *row_buf= m_multi_range_result_ptr;
+ int expected_range_no= first_running_range - first_range_in_batch;
+
+ switch (multi_range_entry_type(row_buf))
+ {
+ case enum_skip_range:
+ case enum_empty_unique_range:
+ /* Nothing in this range; continue with next. */
+ break;
+
+ case enum_unique_range:
+ /*
+ Move to next range; we can have at most one record from a unique
+ range.
+ */
+ first_running_range++;
+ m_multi_range_result_ptr=
+ multi_range_next_entry(m_multi_range_result_ptr,
+ table_share->reclength);
+
+ /*
+ Clear m_active_cursor; it is used as a flag in update_row() /
+ delete_row() to know whether the current tuple is from a scan
+ or pk operation.
+ */
+ m_active_cursor= NULL;
+
+ /* Return the record. */
+ *range_info= multi_range_get_custom(multi_range_buffer,
+ expected_range_no);
+ memcpy(table->record[0], multi_range_row(row_buf),
+ table_share->reclength);
+ DBUG_RETURN(0);
+
+ case enum_ordered_range:
+ /* An index scan range. */
+ {
+ int res;
+ if ((res= read_multi_range_fetch_next()) != 0)
+ {
+ *range_info= multi_range_get_custom(multi_range_buffer,
+ expected_range_no);
+ first_running_range++;
+ m_multi_range_result_ptr=
+ multi_range_next_entry(m_multi_range_result_ptr,
+ table_share->reclength);
+ DBUG_RETURN(res);
+ }
+ }
+ if (!m_next_row)
+ {
+ /*
+ The whole scan is done, and the cursor has been closed.
+ So nothing more for this range. Move to next.
+ */
+ break;
+ }
+ else
+ {
+ int current_range_no= m_current_range_no;
+ /*
+ For a sorted index scan, we will receive rows in increasing
+ range_no order, so we can return ranges in order, pausing when
+ range_no indicate that the currently processed range
+ (first_running_range) is done.
+
+ But for unsorted scan, we may receive a high range_no from one
+ fragment followed by a low range_no from another fragment. So we
+ need to process all index scan ranges together.
+ */
+ if (!mrr_is_output_sorted || expected_range_no == current_range_no)
+ {
+ *range_info= multi_range_get_custom(multi_range_buffer,
+ current_range_no);
+ /* Copy out data from the new row. */
+ unpack_record(table->record[0], m_next_row);
+ table->status= 0;
+ /*
+ Mark that we have used this row, so we need to fetch a new
+ one on the next call.
+ */
+ m_next_row= 0;
+ /*
+ Set m_active_cursor; it is used as a flag in update_row() /
+ delete_row() to know whether the current tuple is from a scan or
+ pk operation.
+ */
+ m_active_cursor= m_multi_cursor;
+
+ DBUG_RETURN(0);
+ }
+ else if (current_range_no > expected_range_no)
+ {
+ /* Nothing more in scan for this range. Move to next. */
+ break;
+ }
+ else
+ {
+ /*
+ Should not happen. Ranges should be returned from NDB API in
+ the order we requested them.
+ */
+ DBUG_ASSERT(0);
+ break; // Attempt to carry on
+ }
+ }
+
+ default:
+ DBUG_ASSERT(0);
+ }
+ /* At this point the current range is done, proceed to next. */
+ first_running_range++;
+ m_multi_range_result_ptr=
+ multi_range_next_entry(m_multi_range_result_ptr, table_share->reclength);
+ }
+
+ if (first_running_range == ranges_in_seq)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ /*
+ Read remaining ranges
+ */
+ if ((res= multi_range_start_retrievals(first_running_range)))
+ DBUG_RETURN(res);
+
+ }
+}
+
+#else // not 'NDB_WITH_NEW_MRR_INTERFACE'
+
/*
This is used to check if an ordered index scan is needed for a range in
a multi range read.
@@ -15145,6 +16047,7 @@ ha_ndbcluster::read_multi_range_next(KEY
multi_range_sorted,
multi_range_buffer));
}
+#endif
/*
Fetch next row from the ordered index cursor in multi range scan.
@@ -15213,7 +16116,6 @@ ha_ndbcluster::read_multi_range_fetch_ne
}
DBUG_RETURN(0);
}
-#endif
#ifndef NDB_WITHOUT_JOIN_PUSHDOWN
=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h 2011-10-05 07:24:39 +0000
+++ b/sql/ha_ndbcluster.h 2011-10-18 10:43:35 +0000
@@ -345,19 +345,28 @@ class ha_ndbcluster: public handler
uchar* buf);
int read_range_next();
-#ifndef NDB_WITH_NEW_MRR_INTERFACE
/**
- * Multi range stuff
+ * Multi Range Read interface
*/
- int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
- KEY_MULTI_RANGE*ranges, uint range_count,
- bool sorted, HANDLER_BUFFER *buffer);
- int read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
- bool null_value_index_search(KEY_MULTI_RANGE *ranges,
- KEY_MULTI_RANGE *end_range,
- HANDLER_BUFFER *buffer);
-#endif
+ int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode, HANDLER_BUFFER *buf);
+ int multi_range_read_next(char **range_info);
+ ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint *bufsz,
+ uint *flags, COST_VECT *cost);
+ ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+ uint *bufsz, uint *flags, COST_VECT *cost);
+private:
+ uint first_running_range;
+ uint first_range_in_batch;
+ uint first_unstarted_range;
+ /* TRUE <=> need range association */
+ bool mrr_need_range_assoc;
+
+ int multi_range_start_retrievals(uint first_range);
+public:
bool get_error_message(int error, String *buf);
ha_rows records();
ha_rows estimate_rows_upper_bound()
@@ -806,7 +815,8 @@ private:
};
/* For read_multi_range scans, the get_range_no() of current row. */
int m_current_range_no;
-
+ /* For multi range read, return from last mrr_funcs.next() call. */
+ int m_range_res;
MY_BITMAP **m_key_fields;
// NdbRecAttr has no reference to blob
NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE];
@@ -860,14 +870,7 @@ private:
ha_ndbcluster_cond *m_cond;
bool m_disable_multi_read;
- const uchar *m_multi_range_result_ptr;
- KEY_MULTI_RANGE *m_multi_ranges;
- /*
- Points 1 past the end of last multi range operation currently being
- executed, to support splitting large multi range reands into manageable
- pieces.
- */
- KEY_MULTI_RANGE *m_multi_range_defined_end;
+ uchar *m_multi_range_result_ptr;
NdbIndexScanOperation *m_multi_cursor;
Ndb *get_ndb(THD *thd);
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2011-10-05 07:24:39 +0000
+++ b/sql/handler.cc 2011-10-18 10:43:35 +0000
@@ -3322,8 +3322,6 @@ err:
*/
uint handler::get_dup_key(int error)
{
- DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE ||
- m_lock_type != F_UNLCK);
DBUG_ENTER("handler::get_dup_key");
#ifndef MCP_BUG59948
if (table == NULL || table->file == NULL)
@@ -3338,6 +3336,8 @@ uint handler::get_dup_key(int error)
DBUG_RETURN(-1);
}
#endif
+ DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE ||
+ m_lock_type != F_UNLCK);
table->file->errkey = (uint) -1;
if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOREIGN_DUPLICATE_KEY ||
error == HA_ERR_FOUND_DUPP_UNIQUE || error == HA_ERR_NULL_IN_SPATIAL ||
=== modified file 'storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp 2011-09-29 09:23:04 +0000
+++ b/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp 2011-10-18 10:43:35 +0000
@@ -235,6 +235,14 @@ public:
Uint32 sizeOfPartInfo= 0);
/**
+ * Return size of data, in 32-bit words, that will be send to data nodes for
+ * all bounds added so far with setBound().
+ *
+ * This method is only available for NdbRecord index scans.
+ */
+ int getCurrentKeySize();
+
+ /**
* Is current scan sorted?
*/
bool getSorted() const { return m_ordered; }
=== modified file 'storage/ndb/src/ndbapi/NdbScanOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbScanOperation.cpp 2011-05-20 05:54:20 +0000
+++ b/storage/ndb/src/ndbapi/NdbScanOperation.cpp 2011-10-18 10:43:35 +0000
@@ -3445,6 +3445,20 @@ NdbIndexScanOperation::insert_open_bound
return 0;
}
+
+int
+NdbIndexScanOperation::getCurrentKeySize()
+{
+ if (unlikely((theStatus != NdbOperation::UseNdbRecord)))
+ {
+ setErrorCodeAbort(4284);
+ /* Cannot mix NdbRecAttr and NdbRecord methods in one operation */
+ return -1;
+ }
+ return theTupKeyLen;
+}
+
+
/* IndexScan readTuples - part of old scan API
* This call does the minimum amount of validation and state
* storage possible. Most of the scan initialisation is done
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk-cluster branch (ole.john.aske:3392 to 3393) | Ole John Aske | 18 Oct |