List:Commits« Previous MessageNext Message »
From:Ole John Aske Date:October 18 2011 10:44am
Subject:bzr push into mysql-trunk-cluster branch (ole.john.aske:3392 to 3393)
View as plain text  
 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 Aske18 Oct