summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdebian/autobake-deb.sh39
-rw-r--r--debian/mariadb-server-10.8.mariadb.init15
-rwxr-xr-xdebian/rules21
-rw-r--r--debian/salsa-ci.yml77
-rw-r--r--debian/source/lintian-overrides2
-rw-r--r--debian/tests/upstream24
-rw-r--r--mysql-test/suite/binlog/r/binlog_empty_xa_prepared.result1
-rw-r--r--mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_binary.result1
-rw-r--r--mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_ucs2.result1
-rw-r--r--mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_utf32.result1
-rw-r--r--mysql-test/suite/binlog/t/binlog_empty_xa_prepared.test2
-rw-r--r--mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_binary.test1
-rw-r--r--mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_ucs2.test1
-rw-r--r--mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_utf32.test1
-rw-r--r--mysql-test/suite/compat/oracle/r/sp-package.result75
-rw-r--r--mysql-test/suite/compat/oracle/t/sp-package.test72
-rw-r--r--mysql-test/suite/encryption/t/innochecksum.test14
-rw-r--r--mysql-test/suite/innodb/r/insert_into_empty,32k.rdiff9
-rw-r--r--mysql-test/suite/innodb/r/insert_into_empty,64k.rdiff9
-rw-r--r--mysql-test/suite/innodb/r/insert_into_empty.result29
-rw-r--r--mysql-test/suite/innodb/r/insert_into_empty_notembedded.result30
-rw-r--r--mysql-test/suite/innodb/r/temporary_table.result12
-rw-r--r--mysql-test/suite/innodb/t/insert_into_empty.test35
-rw-r--r--mysql-test/suite/innodb/t/insert_into_empty_notembedded.test43
-rw-r--r--mysql-test/suite/innodb/t/temporary_table.test11
-rw-r--r--mysql-test/suite/maria/rollback.result1
-rw-r--r--mysql-test/suite/maria/rollback.test2
-rw-r--r--mysql-test/suite/mariabackup/defer_space.result3
-rw-r--r--mysql-test/suite/mariabackup/defer_space.test18
-rw-r--r--mysql-test/suite/sys_vars/t/wsrep_on_without_provider.test1
-rw-r--r--mysql-test/suite/versioning/r/partition.result14
-rw-r--r--mysql-test/suite/versioning/t/partition.test12
-rw-r--r--mysys/my_gethwaddr.c2
-rw-r--r--sql/partition_info.h5
-rw-r--r--sql/share/errmsg-utf8.txt6
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_partition.cc108
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_yacc.yy6
-rw-r--r--storage/innobase/CMakeLists.txt4
-rw-r--r--storage/innobase/btr/btr0btr.cc437
-rw-r--r--storage/innobase/btr/btr0bulk.cc1
-rw-r--r--storage/innobase/btr/btr0cur.cc840
-rw-r--r--storage/innobase/btr/btr0defragment.cc11
-rw-r--r--storage/innobase/btr/btr0pcur.cc103
-rw-r--r--storage/innobase/btr/btr0sea.cc177
-rw-r--r--storage/innobase/buf/buf0flu.cc13
-rw-r--r--storage/innobase/dict/dict0crea.cc7
-rw-r--r--storage/innobase/dict/dict0dict.cc6
-rw-r--r--storage/innobase/dict/dict0load.cc35
-rw-r--r--storage/innobase/dict/dict0stats.cc129
-rw-r--r--storage/innobase/fil/fil0crypt.cc1
-rw-r--r--storage/innobase/fts/fts0fts.cc17
-rw-r--r--storage/innobase/gis/gis0rtree.cc158
-rw-r--r--storage/innobase/gis/gis0sea.cc85
-rw-r--r--storage/innobase/handler/ha_innodb.cc18
-rw-r--r--storage/innobase/handler/handler0alter.cc9
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc206
-rw-r--r--storage/innobase/include/btr0btr.h136
-rw-r--r--storage/innobase/include/btr0btr.inl40
-rw-r--r--storage/innobase/include/btr0cur.h74
-rw-r--r--storage/innobase/include/btr0cur.inl12
-rw-r--r--storage/innobase/include/btr0pcur.h249
-rw-r--r--storage/innobase/include/btr0pcur.inl107
-rw-r--r--storage/innobase/include/btr0types.h96
-rw-r--r--storage/innobase/include/dyn0buf.h58
-rw-r--r--storage/innobase/include/gis0rtree.h22
-rw-r--r--storage/innobase/include/ibuf0ibuf.h38
-rw-r--r--storage/innobase/include/ibuf0ibuf.inl31
-rw-r--r--storage/innobase/include/ibuf0types.h31
-rw-r--r--storage/innobase/include/log0log.h5
-rw-r--r--storage/innobase/include/mtr0mtr.h264
-rw-r--r--storage/innobase/include/mtr0mtr.inl179
-rw-r--r--storage/innobase/include/page0cur.h22
-rw-r--r--storage/innobase/include/page0cur.inl21
-rw-r--r--storage/innobase/include/row0ins.h8
-rw-r--r--storage/innobase/include/row0row.h13
-rw-r--r--storage/innobase/log/log0log.cc14
-rw-r--r--storage/innobase/log/log0recv.cc21
-rw-r--r--storage/innobase/mtr/mtr0mtr.cc1458
-rw-r--r--storage/innobase/page/page0cur.cc32
-rw-r--r--storage/innobase/page/page0page.cc17
-rw-r--r--storage/innobase/que/que0que.cc8
-rw-r--r--storage/innobase/rem/rem0rec.cc4
-rw-r--r--storage/innobase/row/row0import.cc30
-rw-r--r--storage/innobase/row/row0ins.cc160
-rw-r--r--storage/innobase/row/row0log.cc41
-rw-r--r--storage/innobase/row/row0merge.cc17
-rw-r--r--storage/innobase/row/row0mysql.cc16
-rw-r--r--storage/innobase/row/row0purge.cc25
-rw-r--r--storage/innobase/row/row0row.cc52
-rw-r--r--storage/innobase/row/row0sel.cc88
-rw-r--r--storage/innobase/row/row0uins.cc31
-rw-r--r--storage/innobase/row/row0umod.cc56
-rw-r--r--storage/innobase/row/row0upd.cc23
-rw-r--r--storage/innobase/srv/srv0srv.cc73
-rw-r--r--storage/innobase/trx/trx0trx.cc2
98 files changed, 2997 insertions, 3548 deletions
diff --git a/debian/autobake-deb.sh b/debian/autobake-deb.sh
index 9cde381b91b..09b06084647 100755
--- a/debian/autobake-deb.sh
+++ b/debian/autobake-deb.sh
@@ -26,9 +26,9 @@ then
sed '/Add support for verbose builds/,/^$/d' -i debian/rules
elif [ -d storage/columnstore/columnstore/debian ]
then
- # ColumnStore is explicitly disabled in the native Debian build, so allow it
+ # ColumnStore is explicitly disabled in the native Debian build. Enable it
# now when build is triggered by autobake-deb.sh (MariaDB.org) and when the
- # build is not running on Travis or Gitlab-CI
+ # build is not running on Gitlab-CI.
sed '/-DPLUGIN_COLUMNSTORE=NO/d' -i debian/rules
# Take the files and part of control from MCS directory
if [ ! -f debian/mariadb-plugin-columnstore.install ]
@@ -59,13 +59,13 @@ replace_uring_with_aio()
{
sed 's/liburing-dev/libaio-dev/g' -i debian/control
sed -e '/-DIGNORE_AIO_CHECK=YES/d' \
- -e '/-DWITH_URING=yes/d' -i debian/rules
+ -e '/-DWITH_URING=YES/d' -i debian/rules
}
disable_pmem()
{
sed '/libpmem-dev/d' -i debian/control
- sed '/-DWITH_PMEM=yes/d' -i debian/rules
+ sed '/-DWITH_PMEM=YES/d' -i debian/rules
}
disable_libfmt()
@@ -76,15 +76,34 @@ disable_libfmt()
architecture=$(dpkg-architecture -q DEB_BUILD_ARCH)
+# Parse release name and number from Linux standard base release
+# Example:
+# $ lsb_release -a
+# No LSB modules are available.
+# Distributor ID: Debian
+# Description: Debian GNU/Linux bookworm/sid
+# Release: n/a
+# Codename: n/a
LSBID="$(lsb_release -si | tr '[:upper:]' '[:lower:]')"
LSBVERSION="$(lsb_release -sr | sed -e "s#\.##g")"
LSBNAME="$(lsb_release -sc)"
+# If 'n/a', assume 'sid'
+if [ "${LSBVERSION}" == "n/a" ] || [ "${LSBNAME}" == "n/a" ]
+then
+ LSBVERSION="sid"
+ LSBNAME="sid"
+fi
+
+# If not known, use 'unknown' in .deb version identifier
if [ -z "${LSBID}" ]
then
LSBID="unknown"
fi
-case "${LSBNAME}" in
+
+case "${LSBNAME}"
+in
+ # Debian
stretch)
# MDEV-16525 libzstd-dev-1.1.3 minimum version
sed -e '/libzstd-dev/d' \
@@ -113,10 +132,10 @@ case "${LSBNAME}" in
fi
;&
sid)
- # should always be empty here.
- # need to match here to avoid the default Error however
+ # The default packaging should always target Debian Sid, so in this case
+ # there is intentionally no customizations whatsoever.
;;
- # UBUNTU
+ # Ubuntu
bionic)
remove_rocksdb_tools
[ "$architecture" != amd64 ] && disable_pmem
@@ -143,7 +162,7 @@ case "${LSBNAME}" in
fi
;;
*)
- echo "Error - unknown release codename $LSBNAME" >&2
+ echo "Error: Unknown release '$LSBNAME'" >&2
exit 1
esac
@@ -162,7 +181,7 @@ LOGSTRING="MariaDB build"
EPOCH="1:"
VERSION="${EPOCH}${UPSTREAM}${PATCHLEVEL}~${LSBID:0:3}${LSBVERSION}"
-dch -b -D ${LSBNAME} -v "${VERSION}" "Automatic build with ${LOGSTRING}." --controlmaint
+dch -b -D "${LSBNAME}" -v "${VERSION}" "Automatic build with ${LOGSTRING}." --controlmaint
echo "Creating package version ${VERSION} ... "
diff --git a/debian/mariadb-server-10.8.mariadb.init b/debian/mariadb-server-10.8.mariadb.init
index 90a99cca873..aa06221a069 100644
--- a/debian/mariadb-server-10.8.mariadb.init
+++ b/debian/mariadb-server-10.8.mariadb.init
@@ -21,9 +21,18 @@ test -x /usr/sbin/mariadbd || exit 0
. /lib/lsb/init-functions
-SELF=$(cd $(dirname $0); pwd -P)/$(basename $0)
-
-MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+SELF=$(cd "$(dirname $0)"; pwd -P)/$(basename $0)
+
+if [ -f /usr/bin/mariadb-admin ]
+then
+ MYADMIN="/usr/bin/mariadb-admin --defaults-file=/etc/mysql/debian.cnf"
+elif [ -f /usr/bin/mysqladmin ]
+then
+ MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+else
+ log_failure_msg "Command mariadb-admin/mysqladmin not found! This SysV init script depends on it."
+ exit -1
+fi
# priority can be overridden and "-s" adds output to stderr
ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mariadb -i"
diff --git a/debian/rules b/debian/rules
index 2a1db6b4ce2..2bf1c948676 100755
--- a/debian/rules
+++ b/debian/rules
@@ -5,7 +5,13 @@ export DEB_BUILD_HARDENING=1
# enable Debian Hardening
# see: https://wiki.debian.org/Hardening
-export DEB_BUILD_MAINT_OPTIONS = hardening=+all optimize=-lto
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# Disable LTO on Ubuntu, see LP: #1970634 and https://jira.mariadb.org/browse/MDEV-25633
+ifeq ($(shell dpkg-vendor --derives-from Ubuntu && echo yes), yes)
+ export DEB_BUILD_MAINT_OPTIONS += optimize=-lto
+endif
+
DPKG_EXPORT_BUILDFLAGS = 1
# Include all defaults, including buildflags.mk
include /usr/share/dpkg/default.mk
@@ -46,11 +52,6 @@ ifeq (32,$(DEB_HOST_ARCH_BITS))
CMAKEFLAGS += -DPLUGIN_ROCKSDB=NO
endif
-# ColumnStore can build only on amd64 and arm64
-ifneq (,$(filter $(DEB_HOST_ARCH_CPU),amd64 arm64))
- CMAKEFLAGS += -DPLUGIN_COLUMNSTORE=NO
-endif
-
# Cross building requires stack direction instruction
ifneq ($(DEB_BUILD_ARCH),$(DEB_HOST_ARCH))
ifneq (,$(filter $(DEB_HOST_ARCH_CPU),alpha amd64 arm arm64 i386 ia64 m68k mips64el mipsel powerpc ppc64 ppc64el riscv64 s390x sh4 sparc64))
@@ -64,7 +65,7 @@ endif
# Only attempt to build with PMEM on archs that have package libpmem-dev available
# See https://packages.debian.org/search?searchon=names&keywords=libpmem-dev
ifneq (,$(filter $(DEB_HOST_ARCH_CPU),amd64 arm64 ppc64el riscv64))
- CMAKEFLAGS += -DWITH_PMEM=yes
+ CMAKEFLAGS += -DWITH_PMEM=YES
endif
# Add support for verbose builds
@@ -105,9 +106,9 @@ endif
-DBUILD_CONFIG=mysql_release \
-DCONC_DEFAULT_CHARSET=utf8mb4 \
-DPLUGIN_AWS_KEY_MANAGEMENT=NO \
- -DPLUGIN_COLUMNSTORE=NO \
+ -DPLUGIN_COLUMNSTORE=NO \
-DIGNORE_AIO_CHECK=YES \
- -DWITH_URING=yes \
+ -DWITH_URING=YES \
-DDEB=$(DEB_VENDOR)
# This is needed, otherwise 'make test' will run before binaries have been built
@@ -120,6 +121,7 @@ override_dh_auto_build:
override_dh_auto_test:
@echo "RULES.$@"
dh_testdir
+ # Ensure at least an empty file exists
touch mysql-test/unstable-tests
[ ! -f debian/unstable-tests.$(DEB_HOST_ARCH) ] || cat debian/unstable-tests.$(DEB_HOST_ARCH) >> mysql-test/unstable-tests
# Run testsuite
@@ -203,6 +205,7 @@ override_dh_installinit-arch:
dh_installinit --name=mariadb --no-start -- defaults 19 21
dh_systemd_start --restart-after-upgrade
+# Use custom server version string variable
override_dh_gencontrol:
dh_gencontrol -- -Tdebian/substvars
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
index 7aee4490558..c6d58829b3e 100644
--- a/debian/salsa-ci.yml
+++ b/debian/salsa-ci.yml
@@ -16,12 +16,17 @@ variables:
GIT_SUBMODULE_STRATEGY: recursive
SALSA_CI_GBP_BUILDPACKAGE_ARGS: "--git-submodules" # did not apply to extract-sources
+# Extend Salsa-CI build jobs to have longer timeout as the default GitLab
+# timeout (1h) is often not enough
+.build-package:
+ timeout: 3h
+
stages:
- provisioning
- build
- test
- upgrade in Sid
- - upgrade from Bullseye/Buster
+ - upgrade from Bullseye
- upgrade extras
- test extras
- publish # Stage referenced by Salsa-CI template aptly stanza, so must exist even though not used
@@ -134,6 +139,17 @@ blhc:
apt-get update
apt-get install -y apt
+.test-enable-buster-backports-repos: &test-enable-buster-backports-repos |
+ # Enable buster-backports (assumes environment already Debian Buster)
+ echo 'deb http://deb.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/buster-backports.list
+ # Increase default backports priority policy from '100' to '500' so it can actually be used
+ cat << EOF > /etc/apt/preferences.d/enable-backports-to-satisfy-dependencies
+ Package: *
+ Pin: release n=buster-*
+ Pin-Priority: 500
+ EOF
+ apt-get update
+
.test-install: &test-install |
# Install MariaDB built in this commit
apt-get install -y ./*.deb
@@ -213,7 +229,7 @@ fresh install:
script:
- *test-prepare-container
- *test-install
- - service mariadb status # There is no init.d/mysql in MariaDB 10.8
+ - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
- *test-verify-final
variables:
GIT_STRATEGY: none
@@ -234,7 +250,7 @@ mariadb-10.8 Sid upgrade:
script:
- *test-prepare-container
- *test-install
- - service mariadb status # There is no init.d/mysql in MariaDB 10.8
+ - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
- *test-verify-final
variables:
GIT_STRATEGY: none
@@ -243,7 +259,7 @@ mariadb-10.8 Sid upgrade:
- $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
mariadb-10.5 Bullseye to mariadb-10.8 upgrade:
- stage: upgrade from Bullseye/Buster
+ stage: upgrade from Bullseye
needs:
- job: build
image: debian:bullseye
@@ -268,10 +284,12 @@ mariadb-10.5 Bullseye to mariadb-10.8 upgrade:
variables:
- $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
-mariadb-10.3 Buster to mariadb-10.8 upgrade:
- stage: upgrade from Bullseye/Buster
+# Upgrade of libcrypt.so.1 no longer possible from Buster to Sid,
+# so test upgrade only inside Buster (https://bugs.debian.org/993755)
+mariadb-10.3 to mariadb-10.8 upgrade in Buster:
+ stage: upgrade extras
needs:
- - job: build
+ - job: build buster-backports
image: debian:buster
artifacts:
when: always
@@ -284,7 +302,7 @@ mariadb-10.3 Buster to mariadb-10.8 upgrade:
- apt-get install -y 'default-mysql*' 'mariadb-*' 'libmariadb*'
# Verify installation of MariaDB from Buster
- *test-verify-initial
- - *test-enable-sid-repos
+ - *test-enable-buster-backports-repos
- *test-install
- service mysql status
- *test-verify-final
@@ -307,7 +325,7 @@ test basic features:
script:
- *test-prepare-container
- *test-install
- - service mariadb status # There is no init.d/mysql in MariaDB 10.8
+ - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
- *test-verify-final
- |
# Print info about server
@@ -452,7 +470,7 @@ default-libmysqlclient-dev Sid upgrade:
- $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
default-libmysqlclient-dev Bullseye upgrade:
- stage: upgrade from Bullseye/Buster
+ stage: upgrade from Bullseye
needs:
- job: build
image: debian:bullseye
@@ -472,10 +490,12 @@ default-libmysqlclient-dev Bullseye upgrade:
variables:
- $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
-default-libmysqlclient-dev Buster upgrade:
- stage: upgrade from Bullseye/Buster
+# Upgrade of libcrypt.so.1 no longer possible from Buster to Sid,
+# so test upgrade only inside Buster (https://bugs.debian.org/993755)
+default-libmysqlclient-dev upgrade in Buster:
+ stage: upgrade extras
needs:
- - job: build
+ - job: build buster-backports
image: debian:buster
artifacts:
when: always
@@ -486,7 +506,7 @@ default-libmysqlclient-dev Buster upgrade:
- *test-prepare-container
- apt-get install -y pkg-config default-libmysqlclient-dev
- pkg-config --list-all
- - *test-enable-sid-repos
+ - *test-enable-buster-backports-repos
- *test-install-all-libs
- *test-verify-libs
except:
@@ -511,8 +531,20 @@ mysql-8.0 Sid to mariadb-10.8 upgrade:
- apt-get install -y procps mysql-server 'libmysqlc*'
- *test-verify-initial
- *test-install
- - service mysql status
+ # The Debian version of MariaDB 10.6 still maintains compatibility and there
+ # running 'service mysql status' in Salsa-CI job 'mysql-8.0 Sid to
+ # mariadb-10.6 upgrade' still works.
+ #
+ # However, due to debian/control changes, the upstream MariaDB 10.6 when
+ # installed on a system with a previous installation of MySQL 8.0 will first
+ # fully remove MySQL, including the /etc/init.d/mysql file, so previous
+ # techniques in mariadb-server-10.6.postinst to maintain backwards
+ # compatibility with 'service mysql status' after installing MariaDB on top
+ # MySQL no longer works, and thus the step to test it now intentionally has
+ # a fallback to use the service name 'mariadb' instead, and the fallback is
+ # always used.
- sleep 5 # Give the mysql_upgrade a bit of time to complete before querying the server
+ - service mysql status || service mariadb status
- *test-verify-final
variables:
GIT_STRATEGY: none
@@ -522,7 +554,7 @@ mysql-8.0 Sid to mariadb-10.8 upgrade:
# Upgrading from MySQL 8.0 with datadir in place is not possible. Users need to do a data dump.
# The Debian maintainer scripts detect this situation and simply moves old datadir aside and start fresh.
-mysql-8.0 Focal to mariadb-10.8 upgrade:
+mysql-8.0 Focal to mariadb-10.8 upgrade in Buster:
stage: upgrade extras
needs:
- job: build buster-backports
@@ -622,18 +654,13 @@ mariadb.org-10.6 to mariadb-10.8 upgrade:
# Verify installation of MariaDB built in this commit
- dpkg -l | grep -iE 'maria|mysql|galera' || true # List installed
- mariadb --version # Client version
- - service mariadb status # There is no init.d/mysql in MariaDB 10.8
+ - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
- *test-verify-final
variables:
GIT_STRATEGY: none
except:
variables:
- $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
- allow_failure: true
- # Installation on Sid fails on missing liburing1 because upstream 10.8
- # MariaDB.org buildbot has not run 'apt upgrade' for a long time.
- # Remove this allow_failure once buildbot has built a new 10.8
- # release using latest liburing-dev in Debian Sid.
mariadb.org-10.5 to mariadb-10.8 upgrade:
stage: upgrade extras
@@ -657,7 +684,7 @@ mariadb.org-10.5 to mariadb-10.8 upgrade:
# Verify installation of MariaDB built in this commit
- dpkg -l | grep -iE 'maria|mysql|galera' || true # List installed
- mariadb --version # Client version
- - service mariadb status # There is no init.d/mysql in MariaDB 10.5
+ - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
- *test-verify-final
variables:
GIT_STRATEGY: none
@@ -768,7 +795,7 @@ mariadb.org-10.2 to mariadb-10.8 upgrade:
variables:
- $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
-mysql.com-5.7 to mariadb-10.8 upgrade:
+mysql.com-5.7 to mariadb-10.8 upgrade in Buster:
stage: upgrade extras
needs:
- job: build buster-backports
@@ -799,7 +826,7 @@ mysql.com-5.7 to mariadb-10.8 upgrade:
variables:
- $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
-percona-xtradb-5.7 to mariadb-10.8 upgrade (MDEV-22679):
+percona-xtradb-5.7 to mariadb-10.8 upgrade in Buster (MDEV-22679):
stage: upgrade extras
needs:
- job: build buster-backports
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
index 998aa4810b1..ab472d4237a 100644
--- a/debian/source/lintian-overrides
+++ b/debian/source/lintian-overrides
@@ -48,7 +48,7 @@ very-long-line-length-in-source-file mysql-test/std_data/init_file_longline_3816
very-long-line-length-in-source-file scripts/fill_help_tables.sql *
very-long-line-length-in-source-file scripts/mysql_system_tables.sql *
very-long-line-length-in-source-file scripts/mysql_test_data_timezone.sql *
-# Machine formated HTML
+# Machine formatted HTML
very-long-line-length-in-source-file sql/share/charsets/languages.html *
very-long-line-length-in-source-file sql/share/errmsg-utf8.txt *
# Very long test string
diff --git a/debian/tests/upstream b/debian/tests/upstream
index f216df24371..c48701864b7 100644
--- a/debian/tests/upstream
+++ b/debian/tests/upstream
@@ -10,6 +10,8 @@ echo "Running test 'testsuite'"
set -e
SKIP_TEST_LST="/tmp/skip-test.lst"
+ARCH=$(dpkg --print-architecture)
+
WORKDIR=$(mktemp -d)
trap 'rm -rf $WORKDIR $SKIP_TEST_LST' 0 INT QUIT ABRT PIPE TERM
cd "$WORKDIR"
@@ -22,16 +24,15 @@ echo "using tmpdir: $WORKDIR/tmp"
echo "Setting up skip-tests-list"
-touch $SKIP_TEST_LST
+# Use unstable-tests list as base to skip all tests considered unstable
+# or create an empty file if that upstream file does not exists on this branch
+cp /usr/share/mysql/mysql-test/unstable-tests $SKIP_TEST_LST || touch $SKIP_TEST_LST
-# Also use arch specific skiplists if such files exist
-for filename in /usr/share/mysql/mysql-test/unstable-tests.*
-do
- # Check for case that no files matched and glob is returned
- [ -e "$filename" ] || continue
- # Append file to the main skip test list file
- cat "$filename" >> $SKIP_TEST_LST
-done
+# Also use the arch specific skiplists if exist
+if [ -f /usr/share/mysql/mysql-test/unstable-tests.$ARCH ]
+then
+ cat /usr/share/mysql/mysql-test/unstable-tests.$ARCH >> $SKIP_TEST_LST
+fi
# Skip tests that cannot run properly on ci.debian.net / autopkgtests.ubuntu.com
cat >> $SKIP_TEST_LST << EOF
@@ -48,7 +49,6 @@ main.mysqld--help : For unknown reason table-cache is 4000 instead of default 42
EOF
fi
-ARCH=$(dpkg --print-architecture)
if [ "$ARCH" = "s390x" ]
then
echo "main.func_regexp_pcre : recursion fails on s390x https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1723947" >> $SKIP_TEST_LST
@@ -57,6 +57,10 @@ then
echo "main.failed_auth_unixsocket : Test returns wrong exit code on armhf and i386 (but only in debci) https://jira.mariadb.org/browse/MDEV-23933" >> $SKIP_TEST_LST
fi
+# Store skipped test list in artifacts so it can be viewed while debugging
+# failed autopkgtest runs
+cp -v $SKIP_TEST_LST $AUTOPKGTEST_ARTIFACTS
+
cd /usr/share/mysql/mysql-test
echo "starting mysql-test-tun.pl..."
eatmydata perl -I. ./mysql-test-run.pl --suite=main \
diff --git a/mysql-test/suite/binlog/r/binlog_empty_xa_prepared.result b/mysql-test/suite/binlog/r/binlog_empty_xa_prepared.result
index 589570d8300..b11484367b8 100644
--- a/mysql-test/suite/binlog/r/binlog_empty_xa_prepared.result
+++ b/mysql-test/suite/binlog/r/binlog_empty_xa_prepared.result
@@ -1,3 +1,4 @@
+RESET MASTER;
CREATE TEMPORARY SEQUENCE seq_1;
XA START '3';
CREATE TEMPORARY TABLE tmp_1(c INT);
diff --git a/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_binary.result b/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_binary.result
index 789bc6cd178..7514380b715 100644
--- a/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_binary.result
+++ b/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_binary.result
@@ -1,3 +1,4 @@
+RESET MASTER;
#
# Verify that SET string values and character sets can be printed correctly
#
diff --git a/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_ucs2.result b/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_ucs2.result
index 1b1d2a79725..a889a2fa82e 100644
--- a/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_ucs2.result
+++ b/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_ucs2.result
@@ -1,3 +1,4 @@
+RESET MASTER;
#
# Verify that SET string values and character sets can be printed correctly
#
diff --git a/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_utf32.result b/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_utf32.result
index 6fdda842bac..e44d0a275d7 100644
--- a/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_utf32.result
+++ b/mysql-test/suite/binlog/r/binlog_table_map_optional_metadata_utf32.result
@@ -1,3 +1,4 @@
+RESET MASTER;
#
# Verify that SET string values and character sets can be printed correctly
#
diff --git a/mysql-test/suite/binlog/t/binlog_empty_xa_prepared.test b/mysql-test/suite/binlog/t/binlog_empty_xa_prepared.test
index 2890c42a087..b127178ebf7 100644
--- a/mysql-test/suite/binlog/t/binlog_empty_xa_prepared.test
+++ b/mysql-test/suite/binlog/t/binlog_empty_xa_prepared.test
@@ -4,7 +4,7 @@
--source include/have_binlog_format_mixed.inc
--source include/have_innodb.inc
-
+RESET MASTER; # clear binlogs
# MDEV-22420 DDL on temporary object is prohibited when XA is in prepare state
# Temporary sequnce may not be created within a transaction
diff --git a/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_binary.test b/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_binary.test
index 5997cfd5d27..29e10ede98a 100644
--- a/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_binary.test
+++ b/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_binary.test
@@ -20,6 +20,7 @@
--let $MYSQLD_DATADIR= `select @@datadir`
--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
+RESET MASTER;
--echo #
--echo # Verify that SET string values and character sets can be printed correctly
--echo #
diff --git a/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_ucs2.test b/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_ucs2.test
index 1e218acdfea..8c9e22421b6 100644
--- a/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_ucs2.test
+++ b/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_ucs2.test
@@ -21,6 +21,7 @@
--let $MYSQLD_DATADIR= `select @@datadir`
--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
+RESET MASTER;
--echo #
--echo # Verify that SET string values and character sets can be printed correctly
--echo #
diff --git a/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_utf32.test b/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_utf32.test
index c1d449abf2f..094de058028 100644
--- a/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_utf32.test
+++ b/mysql-test/suite/binlog/t/binlog_table_map_optional_metadata_utf32.test
@@ -21,6 +21,7 @@
--let $MYSQLD_DATADIR= `select @@datadir`
--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
+RESET MASTER;
--echo #
--echo # Verify that SET string values and character sets can be printed correctly
--echo #
diff --git a/mysql-test/suite/compat/oracle/r/sp-package.result b/mysql-test/suite/compat/oracle/r/sp-package.result
index daa244a3c5a..ef0acea5da1 100644
--- a/mysql-test/suite/compat/oracle/r/sp-package.result
+++ b/mysql-test/suite/compat/oracle/r/sp-package.result
@@ -3268,3 +3268,78 @@ a
This is db1.pkg1.p1
DROP DATABASE db1;
DROP DATABASE db2;
+#
+# MDEV-29370 Functions in packages are slow and seems to ignore deterministic
+#
+SET SQL_MODE=ORACLE;
+CREATE TABLE t1 (c1 CHAR(1));
+CREATE FUNCTION f1_deterministic()
+RETURN CHAR(1)
+DETERMINISTIC
+IS
+BEGIN
+RETURN 'X';
+END;
+//
+CREATE FUNCTION f2_not_deterministic()
+RETURN CHAR(1)
+IS
+BEGIN
+RETURN 'X';
+END;
+//
+CREATE PACKAGE pkg1
+IS
+PROCEDURE t1_populate(numrows INTEGER);
+FUNCTION f3_deterministic() RETURN CHAR(1) DETERMINISTIC;
+FUNCTION f4_not_deterministic() RETURN CHAR(1);
+END;
+//
+CREATE PACKAGE BODY pkg1
+IS
+PROCEDURE t1_populate(numrounds INTEGER)
+IS
+i INTEGER;
+BEGIN
+INSERT INTO t1 VALUES('Y');
+FOR i IN 1..numrounds LOOP
+INSERT INTO t1 SELECT * FROM t1;
+END LOOP;
+END;
+FUNCTION f3_deterministic() RETURN CHAR(1) DETERMINISTIC COMMENT 'xxx'
+ IS
+BEGIN
+RETURN 'X';
+END;
+FUNCTION f4_not_deterministic() RETURN CHAR(1)
+IS
+BEGIN
+RETURN 'X';
+END;
+END;
+//
+CALL pkg1.t1_populate(3);
+EXPLAIN EXTENDED SELECT 'Deterministic function', COUNT(*) FROM t1 WHERE c1 = f1_deterministic();
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where
+Warnings:
+Note 1003 select 'Deterministic function' AS "Deterministic function",count(0) AS "COUNT(*)" from "test"."t1" where "test"."t1"."c1" = <cache>("f1_deterministic"())
+EXPLAIN EXTENDED SELECT 'Non-deterministic function', COUNT(*) FROM t1 WHERE c1 = f2_not_deterministic();
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where
+Warnings:
+Note 1003 select 'Non-deterministic function' AS "Non-deterministic function",count(0) AS "COUNT(*)" from "test"."t1" where "test"."t1"."c1" = "f2_not_deterministic"()
+EXPLAIN EXTENDED SELECT 'Deterministic package function', COUNT(*) FROM t1 WHERE c1 = pkg1.f3_deterministic();
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where
+Warnings:
+Note 1003 select 'Deterministic package function' AS "Deterministic package function",count(0) AS "COUNT(*)" from "test"."t1" where "test"."t1"."c1" = <cache>("test"."pkg1"."f3_deterministic"())
+EXPLAIN EXTENDED SELECT 'Non-deterministic package function', COUNT(*) FROM t1 WHERE c1 = pkg1.f4_not_deterministic();
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 8 100.00 Using where
+Warnings:
+Note 1003 select 'Non-deterministic package function' AS "Non-deterministic package function",count(0) AS "COUNT(*)" from "test"."t1" where "test"."t1"."c1" = "test"."pkg1"."f4_not_deterministic"()
+DROP TABLE t1;
+DROP FUNCTION f1_deterministic;
+DROP FUNCTION f2_not_deterministic;
+DROP PACKAGE pkg1;
diff --git a/mysql-test/suite/compat/oracle/t/sp-package.test b/mysql-test/suite/compat/oracle/t/sp-package.test
index 615ce51e195..0092c869d50 100644
--- a/mysql-test/suite/compat/oracle/t/sp-package.test
+++ b/mysql-test/suite/compat/oracle/t/sp-package.test
@@ -3016,3 +3016,75 @@ CALL db2.pkg1.p2_db1_pkg1_p1;
DROP DATABASE db1;
DROP DATABASE db2;
+
+
+--echo #
+--echo # MDEV-29370 Functions in packages are slow and seems to ignore deterministic
+--echo #
+
+SET SQL_MODE=ORACLE;
+
+CREATE TABLE t1 (c1 CHAR(1));
+
+DELIMITER //;
+CREATE FUNCTION f1_deterministic()
+RETURN CHAR(1)
+DETERMINISTIC
+IS
+BEGIN
+ RETURN 'X';
+END;
+//
+
+CREATE FUNCTION f2_not_deterministic()
+RETURN CHAR(1)
+IS
+BEGIN
+ RETURN 'X';
+END;
+//
+
+CREATE PACKAGE pkg1
+IS
+ PROCEDURE t1_populate(numrows INTEGER);
+ FUNCTION f3_deterministic() RETURN CHAR(1) DETERMINISTIC;
+ FUNCTION f4_not_deterministic() RETURN CHAR(1);
+END;
+//
+
+CREATE PACKAGE BODY pkg1
+IS
+ PROCEDURE t1_populate(numrounds INTEGER)
+ IS
+ i INTEGER;
+ BEGIN
+ INSERT INTO t1 VALUES('Y');
+ FOR i IN 1..numrounds LOOP
+ INSERT INTO t1 SELECT * FROM t1;
+ END LOOP;
+ END;
+ FUNCTION f3_deterministic() RETURN CHAR(1) DETERMINISTIC COMMENT 'xxx'
+ IS
+ BEGIN
+ RETURN 'X';
+ END;
+ FUNCTION f4_not_deterministic() RETURN CHAR(1)
+ IS
+ BEGIN
+ RETURN 'X';
+ END;
+END;
+//
+DELIMITER ;//
+
+CALL pkg1.t1_populate(3);
+
+EXPLAIN EXTENDED SELECT 'Deterministic function', COUNT(*) FROM t1 WHERE c1 = f1_deterministic();
+EXPLAIN EXTENDED SELECT 'Non-deterministic function', COUNT(*) FROM t1 WHERE c1 = f2_not_deterministic();
+EXPLAIN EXTENDED SELECT 'Deterministic package function', COUNT(*) FROM t1 WHERE c1 = pkg1.f3_deterministic();
+EXPLAIN EXTENDED SELECT 'Non-deterministic package function', COUNT(*) FROM t1 WHERE c1 = pkg1.f4_not_deterministic();
+
+DROP TABLE t1;
+DROP FUNCTION f1_deterministic;
+DROP FUNCTION f2_not_deterministic;
+DROP PACKAGE pkg1;
diff --git a/mysql-test/suite/encryption/t/innochecksum.test b/mysql-test/suite/encryption/t/innochecksum.test
index 59d90fbb3d7..516bc0733d9 100644
--- a/mysql-test/suite/encryption/t/innochecksum.test
+++ b/mysql-test/suite/encryption/t/innochecksum.test
@@ -9,6 +9,7 @@
-- source include/have_file_key_management_plugin.inc
-- source include/innodb_page_size_small.inc
-- source include/innodb_checksum_algorithm.inc
+-- source include/maybe_debug.inc
if (!$INNOCHECKSUM) {
--echo Need innochecksum binary
@@ -18,6 +19,10 @@ if (!$INNOCHECKSUM) {
--disable_query_log
# This may be triggered on a slow system or one that lacks native AIO.
call mtr.add_suppression("InnoDB: Trying to delete tablespace.*pending operations");
+if ($have_debug) {
+SET GLOBAL DEBUG_DBUG='+d,ib_log_checkpoint_avoid_hard';
+call mtr.add_suppression("InnoDB: Crash recovery is broken due to insufficient innodb_log_file_size");
+}
--enable_query_log
let $checksum_algorithm = `SELECT @@innodb_checksum_algorithm`;
@@ -259,6 +264,15 @@ print FILE pack("H*", "c00lcafedeadb017");
close FILE or die "close";
EOF
+if (0 && $have_debug) { # these messages sometimes fail to appear
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err
+--let SEARCH_PATTERN= InnoDB: Crash recovery is broken due to insufficient innodb_log_file_size; last checkpoint LSN=\\d+, current LSN=\\d+\\. Shutdown is in progress\\..*InnoDB: Crash recovery was broken.*
+--echo # FOUND 1 is expected for both.
+--source include/search_pattern_in_file.inc
+--let SEARCH_PATTERN= InnoDB: Crash recovery was broken
+--source include/search_pattern_in_file.inc
+}
+
-- disable_result_log
--error 1
--exec $INNOCHECKSUM $t1_IBD
diff --git a/mysql-test/suite/innodb/r/insert_into_empty,32k.rdiff b/mysql-test/suite/innodb/r/insert_into_empty,32k.rdiff
new file mode 100644
index 00000000000..9d40decbb30
--- /dev/null
+++ b/mysql-test/suite/innodb/r/insert_into_empty,32k.rdiff
@@ -0,0 +1,9 @@
+@@ -377,8 +377,6 @@
+ c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB;
+ SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT;
+ ALTER TABLE t1 FORCE;
+-Warnings:
+-Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
+ INSERT IGNORE INTO t1 VALUES
+ (1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
+ (2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107));
diff --git a/mysql-test/suite/innodb/r/insert_into_empty,64k.rdiff b/mysql-test/suite/innodb/r/insert_into_empty,64k.rdiff
new file mode 100644
index 00000000000..9d40decbb30
--- /dev/null
+++ b/mysql-test/suite/innodb/r/insert_into_empty,64k.rdiff
@@ -0,0 +1,9 @@
+@@ -377,8 +377,6 @@
+ c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB;
+ SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT;
+ ALTER TABLE t1 FORCE;
+-Warnings:
+-Warning 139 Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
+ INSERT IGNORE INTO t1 VALUES
+ (1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
+ (2, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107));
diff --git a/mysql-test/suite/innodb/r/insert_into_empty.result b/mysql-test/suite/innodb/r/insert_into_empty.result
index 3267eefdc28..dd4451deaa2 100644
--- a/mysql-test/suite/innodb/r/insert_into_empty.result
+++ b/mysql-test/suite/innodb/r/insert_into_empty.result
@@ -186,12 +186,31 @@ DROP TABLE t;
# MDEV-28327 InnoDB persistent statistics fail to update
# after bulk insert
#
-CREATE TABLE t1 (a INT PRIMARY KEY)ENGINE=InnoDB;
+CREATE TABLE t1 (a INT PRIMARY KEY)ENGINE=InnoDB
+STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
INSERT INTO t1 SELECT * FROM seq_1_to_4096;
# Wait till statistics update after bulk insert operation
-SELECT n_rows FROM mysql.innodb_table_stats WHERE TABLE_NAME="t1";
-n_rows
-4096
+SELECT n_rows>=4000 FROM mysql.innodb_table_stats WHERE TABLE_NAME="t1";
+n_rows>=4000
+1
+DROP TABLE t1;
+#
+# MDEV-27214 Import with disabled keys corrupts meta-data like rows, indexes, ...
+#
+SET UNIQUE_CHECKS=0;
+SET FOREIGN_KEY_CHECKS=0;
+CREATE TABLE `t1` (
+`id` int(11) NOT NULL,
+`a` int(11) DEFAULT NULL,
+PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
+INSERT INTO `t1` VALUES (1,2),(2,3),(3,4);
+# Wait till statistics update after bulk insert operation
+SELECT TABLE_ROWS, AVG_ROW_LENGTH>0 FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
+TABLE_ROWS AVG_ROW_LENGTH>0
+3 1
DROP TABLE t1;
# End of 10.6 tests
#
@@ -351,7 +370,7 @@ DROP TABLE t1, t2;
# MDEV-29801 Inconsistent ER_TOO_BIG_ROWSIZE during bulk
# insert operation
#
-call mtr.add_suppression("InnoDB: Cannot add field `c11` in table");
+call mtr.add_suppression("InnoDB: Cannot add field `(c0[36]|c11)` in table");
SET @format= @@innodb_default_row_format;
CREATE TABLE t1 (pk int primary key, c01 text, c02 text, c03 text,
c04 text, c05 text, c06 text, c07 text, c08 text,
diff --git a/mysql-test/suite/innodb/r/insert_into_empty_notembedded.result b/mysql-test/suite/innodb/r/insert_into_empty_notembedded.result
new file mode 100644
index 00000000000..5305b2e7a85
--- /dev/null
+++ b/mysql-test/suite/innodb/r/insert_into_empty_notembedded.result
@@ -0,0 +1,30 @@
+#
+# Start of 10.6 tests
+#
+#
+# MDEV-27214 Import with disabled keys corrupts meta-data like rows, indexes, ...
+#
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (id int, a int,PRIMARY KEY (id)) ENGINE=InnoDB
+STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
+INSERT INTO db1.t1 VALUES (1,2),(2,3),(3,4);
+DROP DATABASE IF EXISTS db1;
+CREATE DATABASE db1;
+# Wait till statistics update after bulk insert operation
+SELECT TABLE_ROWS, AVG_ROW_LENGTH>0 FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='db1';
+TABLE_ROWS AVG_ROW_LENGTH>0
+3 1
+OPTIMIZE TABLE db1.t1;
+Table Op Msg_type Msg_text
+db1.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+db1.t1 optimize status OK
+# Wait till statistics update after bulk insert operation
+SELECT TABLE_ROWS, AVG_ROW_LENGTH>0 FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='db1';
+TABLE_ROWS AVG_ROW_LENGTH>0
+3 1
+DROP DATABASE db1;
+#
+# End of 10.6 tests
+#
diff --git a/mysql-test/suite/innodb/r/temporary_table.result b/mysql-test/suite/innodb/r/temporary_table.result
index a8a073cb257..ffcee726f0d 100644
--- a/mysql-test/suite/innodb/r/temporary_table.result
+++ b/mysql-test/suite/innodb/r/temporary_table.result
@@ -789,4 +789,16 @@ CHECK TABLE t EXTENDED;
Table Op Msg_type Msg_text
test.t check status OK
DROP TEMPORARY TABLE t;
+#
+# MDEV-29978 Corruption errors upon CHECK on temporary InnoDB table
+#
+CREATE TEMPORARY TABLE t (f INT UNIQUE) ENGINE=InnoDB;
+INSERT INTO t (f) VALUES (1),(2);
+CHECK TABLE t;
+Table Op Msg_type Msg_text
+test.t check status OK
+CHECK TABLE t EXTENDED;
+Table Op Msg_type Msg_text
+test.t check status OK
+DROP TEMPORARY TABLE t;
# End of 10.6 tests
diff --git a/mysql-test/suite/innodb/t/insert_into_empty.test b/mysql-test/suite/innodb/t/insert_into_empty.test
index 590f76dca9e..fab1b882868 100644
--- a/mysql-test/suite/innodb/t/insert_into_empty.test
+++ b/mysql-test/suite/innodb/t/insert_into_empty.test
@@ -1,5 +1,5 @@
--source include/have_innodb.inc
-
+--source include/innodb_page_size.inc
--source include/have_sequence.inc
--source include/maybe_debug.inc
--source include/have_partition.inc
@@ -199,15 +199,41 @@ DROP TABLE t;
--echo # MDEV-28327 InnoDB persistent statistics fail to update
--echo # after bulk insert
--echo #
-CREATE TABLE t1 (a INT PRIMARY KEY)ENGINE=InnoDB;
+CREATE TABLE t1 (a INT PRIMARY KEY)ENGINE=InnoDB
+STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
INSERT INTO t1 SELECT * FROM seq_1_to_4096;
--echo # Wait till statistics update after bulk insert operation
let $wait_condition= select n_rows > 100 from mysql.innodb_table_stats
where table_name="t1";
source include/wait_condition.inc;
-SELECT n_rows FROM mysql.innodb_table_stats WHERE TABLE_NAME="t1";
+# At innodb_page_size=4k this will be only 4075, not 4096. Add some slack.
+# This is related to MDEV-24621 and possibly MDEV-26740.
+SELECT n_rows>=4000 FROM mysql.innodb_table_stats WHERE TABLE_NAME="t1";
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-27214 Import with disabled keys corrupts meta-data like rows, indexes, ...
+--echo #
+
+SET UNIQUE_CHECKS=0;
+SET FOREIGN_KEY_CHECKS=0;
+CREATE TABLE `t1` (
+ `id` int(11) NOT NULL,
+ `a` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
+INSERT INTO `t1` VALUES (1,2),(2,3),(3,4);
+--echo # Wait till statistics update after bulk insert operation
+let $wait_condition= select n_rows > 0 from mysql.innodb_table_stats
+where database_name='test' and table_name='t1';
+source include/wait_condition.inc;
+SELECT TABLE_ROWS, AVG_ROW_LENGTH>0 FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
DROP TABLE t1;
+
--echo # End of 10.6 tests
--echo #
@@ -363,13 +389,14 @@ DROP TABLE t1, t2;
--echo # MDEV-29801 Inconsistent ER_TOO_BIG_ROWSIZE during bulk
--echo # insert operation
--echo #
-call mtr.add_suppression("InnoDB: Cannot add field `c11` in table");
+call mtr.add_suppression("InnoDB: Cannot add field `(c0[36]|c11)` in table");
SET @format= @@innodb_default_row_format;
CREATE TABLE t1 (pk int primary key, c01 text, c02 text, c03 text,
c04 text, c05 text, c06 text, c07 text, c08 text,
c09 text, c10 text, c11 text, c12 text) ENGINE=InnoDB;
SET GLOBAL INNODB_DEFAULT_ROW_FORMAT= COMPACT;
+--replace_result 1982 8126 4030 8126
ALTER TABLE t1 FORCE;
INSERT IGNORE INTO t1 VALUES
(1, REPEAT('x',4805), REPEAT('t',2211), REPEAT('u',974), REPEAT('e',871), REPEAT('z',224), REPEAT('j',978), REPEAT('n',190), REPEAT('t',888), REPEAT('x',32768), REPEAT('e',968), REPEAT('b',913), REPEAT('x',12107)),
diff --git a/mysql-test/suite/innodb/t/insert_into_empty_notembedded.test b/mysql-test/suite/innodb/t/insert_into_empty_notembedded.test
new file mode 100644
index 00000000000..267501133ea
--- /dev/null
+++ b/mysql-test/suite/innodb/t/insert_into_empty_notembedded.test
@@ -0,0 +1,43 @@
+--source include/not_embedded.inc
+--source include/have_innodb.inc
+--source include/innodb_page_size.inc
+--source include/maybe_debug.inc
+
+--echo #
+--echo # Start of 10.6 tests
+--echo #
+
+--echo #
+--echo # MDEV-27214 Import with disabled keys corrupts meta-data like rows, indexes, ...
+--echo #
+
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (id int, a int,PRIMARY KEY (id)) ENGINE=InnoDB
+STATS_PERSISTENT=1 STATS_AUTO_RECALC=1;
+INSERT INTO db1.t1 VALUES (1,2),(2,3),(3,4);
+--let $file = $MYSQLTEST_VARDIR/tmp/dump.sql
+--exec $MYSQL_DUMP db1 t1 >$file
+DROP DATABASE IF EXISTS db1;
+
+CREATE DATABASE db1;
+--exec $MYSQL db1 < $file
+--remove_file $file
+--echo # Wait till statistics update after bulk insert operation
+let $wait_condition= select n_rows > 0 from mysql.innodb_table_stats
+where database_name='db1' and table_name='t1';
+source include/wait_condition.inc;
+SELECT TABLE_ROWS, AVG_ROW_LENGTH>0 FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='db1';
+
+OPTIMIZE TABLE db1.t1;
+--echo # Wait till statistics update after bulk insert operation
+let $wait_condition= select n_rows > 0 from mysql.innodb_table_stats
+where database_name='db1' and table_name='t1';
+source include/wait_condition.inc;
+SELECT TABLE_ROWS, AVG_ROW_LENGTH>0 FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='db1';
+DROP DATABASE db1;
+
+--echo #
+--echo # End of 10.6 tests
+--echo #
diff --git a/mysql-test/suite/innodb/t/temporary_table.test b/mysql-test/suite/innodb/t/temporary_table.test
index 0cc3b29feb1..5d7e5d51696 100644
--- a/mysql-test/suite/innodb/t/temporary_table.test
+++ b/mysql-test/suite/innodb/t/temporary_table.test
@@ -624,4 +624,15 @@ UPDATE t SET a=2;
CHECK TABLE t;
CHECK TABLE t EXTENDED;
DROP TEMPORARY TABLE t;
+
+--echo #
+--echo # MDEV-29978 Corruption errors upon CHECK on temporary InnoDB table
+--echo #
+
+CREATE TEMPORARY TABLE t (f INT UNIQUE) ENGINE=InnoDB;
+INSERT INTO t (f) VALUES (1),(2);
+CHECK TABLE t;
+CHECK TABLE t EXTENDED;
+DROP TEMPORARY TABLE t;
+
--echo # End of 10.6 tests
diff --git a/mysql-test/suite/maria/rollback.result b/mysql-test/suite/maria/rollback.result
index 959f596edf2..2e58387ce57 100644
--- a/mysql-test/suite/maria/rollback.result
+++ b/mysql-test/suite/maria/rollback.result
@@ -1,3 +1,4 @@
+reset master;
call mtr.add_suppression("Table was marked as crashed");
call mtr.add_suppression("Checking table: .*");
create table t1 (a int primary key auto_increment, b int) engine=aria transactional= 1;
diff --git a/mysql-test/suite/maria/rollback.test b/mysql-test/suite/maria/rollback.test
index 1469c26eaa2..d42be9274e6 100644
--- a/mysql-test/suite/maria/rollback.test
+++ b/mysql-test/suite/maria/rollback.test
@@ -3,6 +3,8 @@
# no-protocol doesn't print warnings about repaired tables
--source include/no_protocol.inc
+reset master; # clear binlogs
+
call mtr.add_suppression("Table was marked as crashed");
call mtr.add_suppression("Checking table: .*");
diff --git a/mysql-test/suite/mariabackup/defer_space.result b/mysql-test/suite/mariabackup/defer_space.result
index 41239c476e7..6453aff5502 100644
--- a/mysql-test/suite/mariabackup/defer_space.result
+++ b/mysql-test/suite/mariabackup/defer_space.result
@@ -1,6 +1,7 @@
call mtr.add_suppression("InnoDB: Expected tablespace id .*");
# Mariabackup --backup with page0 INIT_PAGE redo record
# and there is no FILE_CREATE for the tablespace t1
+SET @save_dbug = @@SESSION.debug_dbug;
SET DEBUG_DBUG="+d,checkpoint_after_file_create";
CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
@@ -14,7 +15,7 @@ SELECT * FROM t1;
f1
1
DROP TABLE t1;
-SET DEBUG_DBUG="-d,checkpoint_after_file_create";
+SET @@SESSION.DEBUG_DBUG= @save_debug;
# Mariabackup fails after corrupting the page0 in disk
# and there is no INIT_PAGE for page0
CREATE TABLE t1(c INT) ENGINE=INNODB;
diff --git a/mysql-test/suite/mariabackup/defer_space.test b/mysql-test/suite/mariabackup/defer_space.test
index a475b010531..397a1ff5dc2 100644
--- a/mysql-test/suite/mariabackup/defer_space.test
+++ b/mysql-test/suite/mariabackup/defer_space.test
@@ -6,6 +6,7 @@
call mtr.add_suppression("InnoDB: Expected tablespace id .*");
--echo # Mariabackup --backup with page0 INIT_PAGE redo record
--echo # and there is no FILE_CREATE for the tablespace t1
+SET @save_dbug = @@SESSION.debug_dbug;
SET DEBUG_DBUG="+d,checkpoint_after_file_create";
CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
INSERT INTO t1 VALUES(1);
@@ -26,7 +27,7 @@ exec $XTRABACKUP --prepare --target-dir=$targetdir;
SELECT * FROM t1;
DROP TABLE t1;
rmdir $targetdir;
-SET DEBUG_DBUG="-d,checkpoint_after_file_create";
+SET @@SESSION.DEBUG_DBUG= @save_debug;
--echo # Mariabackup fails after corrupting the page0 in disk
--echo # and there is no INIT_PAGE for page0
@@ -39,16 +40,13 @@ let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
--echo # Corrupt the table
perl;
-use strict;
-use warnings;
-use Fcntl qw(:DEFAULT :seek);
-my $page_size = $ENV{INNODB_PAGE_SIZE};
+my $ps = $ENV{INNODB_PAGE_SIZE};
-sysopen FILE, "$ENV{MYSQLD_DATADIR}/test/t1.ibd", O_RDWR
-|| die "Cannot open t1.ibd\n";
-sysseek(FILE, 0, SEEK_SET) || die "Cannot seek t1.ibd\n";
-my $page=chr(0) x $page_size;
-syswrite(FILE, $page, $page_size)==$page_size;
+my $file = "$ENV{MYSQLD_DATADIR}/test/t1.ibd";
+open(FILE, "+<$file") || die "Unable to open $file";
+binmode FILE;
+seek (FILE, 0, SEEK_SET) or die "seek";
+print FILE chr(0x00) x $ps;
close FILE or die "close";
EOF
diff --git a/mysql-test/suite/sys_vars/t/wsrep_on_without_provider.test b/mysql-test/suite/sys_vars/t/wsrep_on_without_provider.test
index 5bee3c9a356..9b32552436f 100644
--- a/mysql-test/suite/sys_vars/t/wsrep_on_without_provider.test
+++ b/mysql-test/suite/sys_vars/t/wsrep_on_without_provider.test
@@ -1,4 +1,5 @@
--source include/not_embedded.inc
+--source include/have_wsrep.inc
#
# @@global.wsrep_on is not allowed if there
diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result
index 8cd6e97f2d4..6feee27818b 100644
--- a/mysql-test/suite/versioning/r/partition.result
+++ b/mysql-test/suite/versioning/r/partition.result
@@ -96,6 +96,16 @@ with system versioning
partition by system_time (
partition p0 history,
partition pn current);
+create or replace table t1 (a int)
+partition by range (a) (
+partition p0 history,
+partition p1 current);
+ERROR HY000: Wrong partition type `SYSTEM_TIME` for partitioning by `RANGE`
+create or replace table t1 (b int)
+partition by range (a) (
+partition p0 current,
+partition p1 history);
+ERROR HY000: Wrong partition type `SYSTEM_TIME` for partitioning by `RANGE`
## ALTER TABLE
alter table t1 add partition (
partition p1 current);
@@ -150,7 +160,7 @@ partition by system_time limit 1;
alter table t1 change x big int;
create or replace table t1 (i int) engine myisam partition by hash(i) partitions 2;
alter table t1 add partition (partition px history);
-ERROR HY000: Wrong partitioning type, expected type: `SYSTEM_TIME`
+ERROR HY000: Wrong partition type `SYSTEM_TIME` for partitioning by `HASH`
## INSERT, UPDATE, DELETE
create or replace table t1 (x int)
with system versioning
@@ -1105,7 +1115,7 @@ drop table t1;
create table t1 (a int) with system versioning partition by system_time
(partition p1 history, partition pn current);
alter table t1 add partition (partition p2);
-ERROR HY000: Wrong partitioning type, expected type: `SYSTEM_TIME`
+ERROR HY000: Wrong partition type `HASH` for partitioning by `SYSTEM_TIME`
# MDEV-17891 Assertion failures in select_insert::abort_result_set and
# mysql_load upon attempt to replace into a full table
set @@max_heap_table_size= 1024*1024;
diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test
index d026ff4e827..29de10e4738 100644
--- a/mysql-test/suite/versioning/t/partition.test
+++ b/mysql-test/suite/versioning/t/partition.test
@@ -106,6 +106,18 @@ partition by system_time (
partition p0 history,
partition pn current);
+--error ER_PARTITION_WRONG_TYPE
+create or replace table t1 (a int)
+partition by range (a) (
+ partition p0 history,
+ partition p1 current);
+
+--error ER_PARTITION_WRONG_TYPE
+create or replace table t1 (b int)
+partition by range (a) (
+ partition p0 current,
+ partition p1 history);
+
--echo ## ALTER TABLE
diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c
index 24054aa4151..1f344af88fd 100644
--- a/mysys/my_gethwaddr.c
+++ b/mysys/my_gethwaddr.c
@@ -116,7 +116,7 @@ my_bool my_gethwaddr(uchar *to)
uint i;
for (i= 0; res && i < ifc.ifc_len / sizeof(ifr[0]); i++)
{
-#if !defined(_AIX) || !defined(__linux__)
+#if defined(_AIX) || defined(__linux__)
#if defined(__linux__)
#define HWADDR_DATA ifr[i].ifr_hwaddr.sa_data
#else
diff --git a/sql/partition_info.h b/sql/partition_info.h
index e95daec7d31..287aa6d2200 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -429,8 +429,13 @@ public:
return NULL;
}
uint next_part_no(uint new_parts) const;
+
+ int gen_part_type(THD *thd, String *str) const;
};
+void part_type_error(THD *thd, partition_info *work_part_info,
+ const char *part_type, partition_info *tab_part_info);
+
uint32 get_next_partition_id_range(struct st_partition_iter* part_iter);
bool check_partition_dirs(partition_info *part_info);
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 4c7f71f4718..de5117e0246 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -9773,9 +9773,9 @@ ER_UNUSED_23
spa "Nunca debería vd de ver esto"
ER_PARTITION_WRONG_TYPE
- chi "错误的分区类型,预期类型:%`s"
- eng "Wrong partitioning type, expected type: %`s"
- spa "Tipo de partición equivocada, tipo esperado: %`s"
+ chi "错误的分区类型,预期类型:%`s for partitioning by %`s"
+ eng "Wrong partition type %`s for partitioning by %`s"
+ spa "Tipo de partición equivocada, tipo esperado: %`s for partitioning by %`s"
WARN_VERS_PART_FULL
chi "版本化表%`s.%`s:partition%`s已满,添加更多历史分区(out of %s)"
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 57f7cfac595..3f4c30d1797 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -9754,6 +9754,7 @@ bool Lex_ident_sys_st::to_size_number(ulonglong *to) const
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
bool LEX::part_values_current(THD *thd)
{
partition_element *elem= part_info->curr_part_elem;
@@ -9761,7 +9762,7 @@ bool LEX::part_values_current(THD *thd)
{
if (unlikely(part_info->part_type != VERSIONING_PARTITION))
{
- my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
+ part_type_error(thd, NULL, "SYSTEM_TIME", part_info);
return true;
}
}
@@ -9788,7 +9789,7 @@ bool LEX::part_values_history(THD *thd)
{
if (unlikely(part_info->part_type != VERSIONING_PARTITION))
{
- my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
+ part_type_error(thd, NULL, "SYSTEM_TIME", part_info);
return true;
}
}
@@ -9809,6 +9810,7 @@ bool LEX::part_values_history(THD *thd)
elem->type= partition_element::HISTORY;
return false;
}
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
bool LEX::last_field_generated_always_as_row_start_or_end(Lex_ident *p,
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6f3467fcd86..c16947edc5a 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -3776,8 +3776,10 @@ public:
bool table_or_sp_used();
bool is_partition_management() const;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
bool part_values_current(THD *thd);
bool part_values_history(THD *thd);
+#endif
/**
@brief check if the statement is a single-level join
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 66af56d2337..9c7f25e8808 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2470,7 +2470,7 @@ end:
@retval != 0 Failure
*/
-static int add_key_with_algorithm(String *str, partition_info *part_info)
+static int add_key_with_algorithm(String *str, const partition_info *part_info)
{
int err= 0;
err+= str->append(STRING_WITH_LEN("KEY "));
@@ -2499,6 +2499,78 @@ char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info,
return res;
}
+
+/*
+ Generate the partition type syntax from the partition data structure.
+
+ @return Operation status.
+ @retval 0 Success
+ @retval > 0 Failure
+ @retval -1 Fatal error
+*/
+
+int partition_info::gen_part_type(THD *thd, String *str) const
+{
+ int err= 0;
+ switch (part_type)
+ {
+ case RANGE_PARTITION:
+ err+= str->append(STRING_WITH_LEN("RANGE "));
+ break;
+ case LIST_PARTITION:
+ err+= str->append(STRING_WITH_LEN("LIST "));
+ break;
+ case HASH_PARTITION:
+ if (linear_hash_ind)
+ err+= str->append(STRING_WITH_LEN("LINEAR "));
+ if (list_of_part_fields)
+ {
+ err+= add_key_with_algorithm(str, this);
+ err+= add_part_field_list(thd, str, part_field_list);
+ }
+ else
+ err+= str->append(STRING_WITH_LEN("HASH "));
+ break;
+ case VERSIONING_PARTITION:
+ err+= str->append(STRING_WITH_LEN("SYSTEM_TIME "));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ /* We really shouldn't get here, no use in continuing from here */
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
+ return -1;
+ }
+ return err;
+}
+
+
+void part_type_error(THD *thd, partition_info *work_part_info,
+ const char *part_type,
+ partition_info *tab_part_info)
+{
+ StringBuffer<256> tab_part_type;
+ if (tab_part_info->gen_part_type(thd, &tab_part_type) < 0)
+ return;
+ tab_part_type.length(tab_part_type.length() - 1);
+ if (work_part_info)
+ {
+ DBUG_ASSERT(!part_type);
+ StringBuffer<256> work_part_type;
+ if (work_part_info->gen_part_type(thd, &work_part_type) < 0)
+ return;
+ work_part_type.length(work_part_type.length() - 1);
+ my_error(ER_PARTITION_WRONG_TYPE, MYF(0), work_part_type.c_ptr(),
+ tab_part_type.c_ptr());
+ }
+ else
+ {
+ DBUG_ASSERT(part_type);
+ my_error(ER_PARTITION_WRONG_TYPE, MYF(0), part_type,
+ tab_part_type.c_ptr());
+ }
+}
+
+
/*
Generate the partition syntax from the partition data structure.
Useful for support of generating defaults, SHOW CREATE TABLES
@@ -2542,34 +2614,10 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
DBUG_ENTER("generate_partition_syntax");
err+= str.append(STRING_WITH_LEN(" PARTITION BY "));
- switch (part_info->part_type)
- {
- case RANGE_PARTITION:
- err+= str.append(STRING_WITH_LEN("RANGE "));
- break;
- case LIST_PARTITION:
- err+= str.append(STRING_WITH_LEN("LIST "));
- break;
- case HASH_PARTITION:
- if (part_info->linear_hash_ind)
- err+= str.append(STRING_WITH_LEN("LINEAR "));
- if (part_info->list_of_part_fields)
- {
- err+= add_key_with_algorithm(&str, part_info);
- err+= add_part_field_list(thd, &str, part_info->part_field_list);
- }
- else
- err+= str.append(STRING_WITH_LEN("HASH "));
- break;
- case VERSIONING_PARTITION:
- err+= str.append(STRING_WITH_LEN("SYSTEM_TIME "));
- break;
- default:
- DBUG_ASSERT(0);
- /* We really shouldn't get here, no use in continuing from here */
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
- DBUG_RETURN(NULL);
- }
+ int err2= part_info->gen_part_type(thd, &str);
+ if (err2 < 0)
+ DBUG_RETURN(NULL);
+ err+= err2;
if (part_info->part_type == VERSIONING_PARTITION)
{
Vers_part_info *vers_info= part_info->vers_info;
@@ -5069,7 +5117,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
else if (thd->work_part_info->part_type == VERSIONING_PARTITION ||
tab_part_info->part_type == VERSIONING_PARTITION)
{
- my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
+ part_type_error(thd, thd->work_part_info, NULL, tab_part_info);
}
else
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 3cab075b944..9b62af8767f 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -7901,6 +7901,7 @@ void append_drop_column(THD *thd, String *str, Field *field)
}
+#ifdef WITH_PARTITION_STORAGE_ENGINE
static inline
void rename_field_in_list(Create_field *field, List<const char> *field_list)
{
@@ -7913,6 +7914,7 @@ void rename_field_in_list(Create_field *field, List<const char> *field_list)
it.replace(field->field_name.str);
}
}
+#endif
/**
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1c13fc1a1e1..e3403b38020 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4803,13 +4803,17 @@ opt_part_values:
part_values_in {}
| CURRENT_SYM
{
+#ifdef WITH_PARTITION_STORAGE_ENGINE
if (Lex->part_values_current(thd))
MYSQL_YYABORT;
+#endif
}
| HISTORY_SYM
{
+#ifdef WITH_PARTITION_STORAGE_ENGINE
if (Lex->part_values_history(thd))
MYSQL_YYABORT;
+#endif
}
| DEFAULT
{
@@ -18874,6 +18878,7 @@ package_implementation_function_body:
sp_head *sp= pkg->m_current_routine->sphead;
thd->lex= pkg->m_current_routine;
sp->reset_thd_mem_root(thd);
+ sp->set_c_chistics(thd->lex->sp_chistics);
sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
sp_body opt_package_routine_end_name
@@ -18892,6 +18897,7 @@ package_implementation_procedure_body:
sp_head *sp= pkg->m_current_routine->sphead;
thd->lex= pkg->m_current_routine;
sp->reset_thd_mem_root(thd);
+ sp->set_c_chistics(thd->lex->sp_chistics);
sp->set_body_start(thd, YYLIP->get_cpp_tok_start());
}
sp_body opt_package_routine_end_name
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
index 7e938010860..49b363b76d3 100644
--- a/storage/innobase/CMakeLists.txt
+++ b/storage/innobase/CMakeLists.txt
@@ -270,8 +270,7 @@ SET(INNOBASE_SOURCES
include/handler0alter.h
include/hash0hash.h
include/ibuf0ibuf.h
- include/ibuf0ibuf.inl/
- include/ibuf0types.h
+ include/ibuf0ibuf.inl
include/lock0iter.h
include/lock0lock.h
include/lock0lock.inl
@@ -289,7 +288,6 @@ SET(INNOBASE_SOURCES
include/mem0mem.inl
include/mtr0log.h
include/mtr0mtr.h
- include/mtr0mtr.inl
include/mtr0types.h
include/os0file.h
include/os0file.inl
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 8f9984acb98..51632c79761 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -726,7 +726,7 @@ btr_page_get_father_node_ptr_func(
btr_cur_t* cursor, /*!< in: cursor pointing to user record,
out: cursor on node pointer record,
its page x-latched */
- ulint latch_mode,/*!< in: BTR_CONT_MODIFY_TREE
+ btr_latch_mode latch_mode,/*!< in: BTR_CONT_MODIFY_TREE
or BTR_CONT_SEARCH_TREE */
mtr_t* mtr) /*!< in: mtr */
{
@@ -748,7 +748,7 @@ btr_page_get_father_node_ptr_func(
const rec_t* user_rec = btr_cur_get_rec(cursor);
ut_a(page_rec_is_user_rec(user_rec));
- if (btr_cur_search_to_nth_level(index, level + 1,
+ if (btr_cur_search_to_nth_level(level + 1,
dict_index_build_node_ptr(index,
user_rec, 0,
heap, level),
@@ -787,44 +787,33 @@ btr_page_get_father_block(
/*======================*/
rec_offs* offsets,/*!< in: work area for the return value */
mem_heap_t* heap, /*!< in: memory heap to use */
- dict_index_t* index, /*!< in: b-tree index */
- buf_block_t* block, /*!< in: child page in the index */
mtr_t* mtr, /*!< in: mtr */
btr_cur_t* cursor) /*!< out: cursor on node pointer record,
its page x-latched */
{
- rec_t* rec
- = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
- block)));
- if (UNIV_UNLIKELY(!rec)) {
- return nullptr;
- }
- btr_cur_position(index, rec, block, cursor);
- return(btr_page_get_father_node_ptr(offsets, heap, cursor, mtr));
+ rec_t *rec=
+ page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame));
+ if (UNIV_UNLIKELY(!rec))
+ return nullptr;
+ cursor->page_cur.rec= rec;
+ return btr_page_get_father_node_ptr(offsets, heap, cursor, mtr);
}
/** Seek to the parent page of a B-tree page.
-@param[in,out] index b-tree
-@param[in] block child page
@param[in,out] mtr mini-transaction
-@param[out] cursor cursor pointing to the x-latched parent page
+@param[in,out] cursor cursor pointing to the x-latched parent page
@return whether the cursor was successfully positioned */
-bool btr_page_get_father(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
- btr_cur_t* cursor)
+bool btr_page_get_father(mtr_t* mtr, btr_cur_t* cursor)
{
- mem_heap_t* heap;
- rec_t* rec
- = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
- block)));
- if (UNIV_UNLIKELY(!rec)) {
- return false;
- }
- btr_cur_position(index, rec, block, cursor);
-
- heap = mem_heap_create(100);
- const bool got = btr_page_get_father_node_ptr(NULL, heap, cursor, mtr);
- mem_heap_free(heap);
- return got;
+ rec_t *rec=
+ page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame));
+ if (UNIV_UNLIKELY(!rec))
+ return false;
+ cursor->page_cur.rec= rec;
+ mem_heap_t *heap= mem_heap_create(100);
+ const bool got= btr_page_get_father_node_ptr(nullptr, heap, cursor, mtr);
+ mem_heap_free(heap);
+ return got;
}
#ifdef UNIV_DEBUG
@@ -1278,19 +1267,18 @@ btr_write_autoinc(dict_index_t* index, ib_uint64_t autoinc, bool reset)
/** Reorganize an index page.
@param cursor index page cursor
-@param index the index that the cursor belongs to
@param mtr mini-transaction */
-static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
- mtr_t *mtr)
+static dberr_t btr_page_reorganize_low(page_cur_t *cursor, mtr_t *mtr)
{
buf_block_t *const block= cursor->block;
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
ut_ad(!is_buf_block_get_page_zip(block));
ut_ad(fil_page_index_page_check(block->page.frame));
- ut_ad(index->is_dummy ||
- block->page.id().space() == index->table->space->id);
- ut_ad(index->is_dummy || block->page.id().page_no() != index->page ||
+ ut_ad(cursor->index->is_dummy ||
+ block->page.id().space() == cursor->index->table->space->id);
+ ut_ad(cursor->index->is_dummy ||
+ block->page.id().page_no() != cursor->index->page ||
!page_has_siblings(block->page.frame));
/* Save the cursor position. */
@@ -1308,8 +1296,8 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
const mtr_log_t log_mode= mtr->set_log_mode(MTR_LOG_NO_REDO);
- page_create(block, mtr, index->table->not_redundant());
- if (index->is_spatial())
+ page_create(block, mtr, cursor->index->table->not_redundant());
+ if (cursor->index->is_spatial())
block->page.frame[FIL_PAGE_TYPE + 1]= byte(FIL_PAGE_RTREE);
static_assert(((FIL_PAGE_INDEX & 0xff00) | byte(FIL_PAGE_RTREE)) ==
@@ -1321,7 +1309,7 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
dberr_t err=
page_copy_rec_list_end_no_locks(block, old,
page_get_infimum_rec(old->page.frame),
- index, mtr);
+ cursor->index, mtr);
mtr->set_log_mode(log_mode);
if (UNIV_UNLIKELY(err != DB_SUCCESS))
@@ -1335,17 +1323,18 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
if (page_get_max_trx_id(block->page.frame))
/* PAGE_MAX_TRX_ID must be zero on non-leaf pages other than
clustered index root pages. */
- ut_ad(dict_index_is_sec_or_ibuf(index)
+ ut_ad(dict_index_is_sec_or_ibuf(cursor->index)
? page_is_leaf(block->page.frame)
- : block->page.id().page_no() == index->page);
+ : block->page.id().page_no() == cursor->index->page);
else
/* PAGE_MAX_TRX_ID is unused in clustered index pages (other than
the root where it is repurposed as PAGE_ROOT_AUTO_INC), non-leaf
pages, and in temporary tables. It was always zero-initialized in
page_create(). PAGE_MAX_TRX_ID must be nonzero on
dict_index_is_sec_or_ibuf() leaf pages. */
- ut_ad(index->table->is_temporary() || !page_is_leaf(block->page.frame) ||
- !dict_index_is_sec_or_ibuf(index));
+ ut_ad(cursor->index->table->is_temporary() ||
+ !page_is_leaf(block->page.frame) ||
+ !dict_index_is_sec_or_ibuf(cursor->index));
#endif
const uint16_t data_size1= page_get_data_size(old->page.frame);
@@ -1369,10 +1358,10 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
else if (!(cursor->rec= page_rec_get_nth(block->page.frame, pos)))
return DB_CORRUPTION;
- if (block->page.id().page_no() != index->page ||
+ if (block->page.id().page_no() != cursor->index->page ||
fil_page_get_type(old->page.frame) != FIL_PAGE_TYPE_INSTANT)
ut_ad(!memcmp(old->page.frame, block->page.frame, PAGE_HEADER));
- else if (!index->is_instant())
+ else if (!cursor->index->is_instant())
{
ut_ad(!memcmp(old->page.frame, block->page.frame, FIL_PAGE_TYPE));
ut_ad(!memcmp(old->page.frame + FIL_PAGE_TYPE + 2,
@@ -1388,7 +1377,7 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
FIL_PAGE_TYPE + old->page.frame, 2);
memcpy_aligned<2>(PAGE_HEADER + PAGE_INSTANT + block->page.frame,
PAGE_HEADER + PAGE_INSTANT + old->page.frame, 2);
- if (!index->table->instant);
+ if (!cursor->index->table->instant);
else if (page_is_comp(block->page.frame))
{
memcpy(PAGE_NEW_INFIMUM + block->page.frame,
@@ -1411,9 +1400,9 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
block->page.frame + PAGE_MAX_TRX_ID + PAGE_HEADER,
PAGE_DATA - (PAGE_MAX_TRX_ID + PAGE_HEADER)));
- if (!index->has_locking());
- else if (index->page == FIL_NULL)
- ut_ad(index->is_dummy);
+ if (!cursor->index->has_locking());
+ else if (cursor->index->page == FIL_NULL)
+ ut_ad(cursor->index->is_dummy);
else
lock_move_reorganize_page(block, old);
@@ -1568,7 +1557,8 @@ btr_page_reorganize_block(
return page_zip_reorganize(block, index, z_level, mtr, true);
page_cur_t cur;
page_cur_set_before_first(block, &cur);
- return btr_page_reorganize_low(&cur, index, mtr);
+ cur.index= index;
+ return btr_page_reorganize_low(&cur, mtr);
}
/*************************************************************//**
@@ -1580,24 +1570,21 @@ be done either within the same mini-transaction, or by invoking
ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
IBUF_BITMAP_FREE is unaffected by reorganization.
+@param cursor page cursor
+@param mtr mini-transaction
@return error code
@retval DB_FAIL if reorganizing a ROW_FORMAT=COMPRESSED page failed */
-dberr_t
-btr_page_reorganize(
-/*================*/
- page_cur_t* cursor, /*!< in/out: page cursor */
- dict_index_t* index, /*!< in: the index tree of the page */
- mtr_t* mtr) /*!< in/out: mini-transaction */
+dberr_t btr_page_reorganize(page_cur_t *cursor, mtr_t *mtr)
{
if (!buf_block_get_page_zip(cursor->block))
- return btr_page_reorganize_low(cursor, index, mtr);
+ return btr_page_reorganize_low(cursor, mtr);
ulint pos= page_rec_get_n_recs_before(cursor->rec);
if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED))
return DB_CORRUPTION;
- dberr_t err= page_zip_reorganize(cursor->block, index, page_zip_level, mtr,
- true);
+ dberr_t err= page_zip_reorganize(cursor->block, cursor->index,
+ page_zip_level, mtr, true);
if (err == DB_FAIL);
else if (!pos)
ut_ad(cursor->rec == page_get_infimum_rec(cursor->block->page.frame));
@@ -2001,7 +1988,7 @@ btr_root_raise_and_insert(
page_cur_set_before_first(root, page_cursor);
node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr,
- index, offsets, heap, 0, mtr);
+ offsets, heap, 0, mtr);
/* The root page should only contain the node pointer
to new_block at this point. Thus, the data should fit. */
@@ -2014,13 +2001,15 @@ btr_root_raise_and_insert(
ibuf_reset_free_bits(new_block);
}
+ page_cursor->block = new_block;
+ page_cursor->index = index;
+
if (tuple) {
ut_ad(dtuple_check_typed(tuple));
/* Reposition the cursor to the child node */
ulint low_match = 0, up_match = 0;
- if (page_cur_search_with_match(new_block, index, tuple,
- PAGE_CUR_LE,
+ if (page_cur_search_with_match(tuple, PAGE_CUR_LE,
&up_match, &low_match,
page_cursor, nullptr)) {
if (err) {
@@ -2029,8 +2018,7 @@ btr_root_raise_and_insert(
return nullptr;
}
} else {
- /* Set cursor to first record on child node */
- page_cur_set_before_first(new_block, page_cursor);
+ page_cursor->rec = page_get_infimum_rec(new_block->page.frame);
}
/* Split the child and insert tuple */
@@ -2061,10 +2049,10 @@ rec_t* btr_page_get_split_rec_to_left(const btr_cur_t* cursor)
So, we can only assert that when the metadata record exists,
index->is_instant() must hold. */
ut_ad(!page_is_leaf(page) || page_has_prev(page)
- || cursor->index->is_instant()
+ || cursor->index()->is_instant()
|| !(rec_get_info_bits(page_rec_get_next_const(
page_get_infimum_rec(page)),
- cursor->index->table->not_redundant())
+ cursor->index()->table->not_redundant())
& REC_INFO_MIN_REC_FLAG));
const rec_t* infimum = page_get_infimum_rec(page);
@@ -2157,14 +2145,14 @@ btr_page_get_split_rec(
page = btr_cur_get_page(cursor);
- insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
+ insert_size = rec_get_converted_size(cursor->index(), tuple, n_ext);
free_space = page_get_free_space_of_empty(page_is_comp(page));
page_zip = btr_cur_get_page_zip(cursor);
if (page_zip) {
/* Estimate the free space of an empty compressed page. */
ulint free_space_zip = page_zip_empty_size(
- cursor->index->n_fields,
+ cursor->index()->n_fields,
page_zip_get_size(page_zip));
if (free_space > (ulint) free_space_zip) {
@@ -2209,9 +2197,10 @@ btr_page_get_split_rec(
/* Include tuple */
incl_data += insert_size;
} else {
- offsets = rec_get_offsets(rec, cursor->index, offsets,
- page_is_leaf(page)
- ? cursor->index->n_core_fields
+ offsets = rec_get_offsets(rec, cursor->index(),
+ offsets, page_is_leaf(page)
+ ? cursor->index()
+ ->n_core_fields
: 0,
ULINT_UNDEFINED, &heap);
incl_data += rec_offs_size(offsets);
@@ -2262,7 +2251,7 @@ btr_page_insert_fits(
on upper half-page, or NULL if
tuple to be inserted should be first */
rec_offs** offsets,/*!< in: rec_get_offsets(
- split_rec, cursor->index); out: garbage */
+ split_rec, cursor->index()); out: garbage */
const dtuple_t* tuple, /*!< in: tuple to insert */
ulint n_ext, /*!< in: number of externally stored columns */
mem_heap_t** heap) /*!< in: temporary memory heap */
@@ -2280,9 +2269,9 @@ btr_page_insert_fits(
ut_ad(!split_rec
|| !page_is_comp(page) == !rec_offs_comp(*offsets));
ut_ad(!split_rec
- || rec_offs_validate(split_rec, cursor->index, *offsets));
+ || rec_offs_validate(split_rec, cursor->index(), *offsets));
- insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
+ insert_size = rec_get_converted_size(cursor->index(), tuple, n_ext);
free_space = page_get_free_space_of_empty(page_is_comp(page));
/* free_space is now the free space of a created new page */
@@ -2296,7 +2285,7 @@ btr_page_insert_fits(
if (!(end_rec = split_rec)) {
end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
- } else if (cmp_dtuple_rec(tuple, split_rec, cursor->index,
+ } else if (cmp_dtuple_rec(tuple, split_rec, cursor->index(),
*offsets) < 0) {
rec = split_rec;
end_rec = page_get_supremum_rec(page);
@@ -2321,9 +2310,9 @@ got_rec:
/* In this loop we calculate the amount of reserved
space after rec is removed from page. */
- *offsets = rec_get_offsets(rec, cursor->index, *offsets,
+ *offsets = rec_get_offsets(rec, cursor->index(), *offsets,
page_is_leaf(page)
- ? cursor->index->n_core_fields
+ ? cursor->index()->n_core_fields
: 0,
ULINT_UNDEFINED, heap);
@@ -2381,8 +2370,9 @@ btr_insert_on_non_leaf_level(
flags |= BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG
| BTR_NO_UNDO_LOG_FLAG;
+ cursor.page_cur.index = index;
- dberr_t err = btr_cur_search_to_nth_level(index, level, tuple, mode,
+ dberr_t err = btr_cur_search_to_nth_level(level, tuple, mode,
BTR_CONT_MODIFY_TREE,
&cursor, mtr);
ut_ad(cursor.flag == BTR_CUR_BINARY);
@@ -2438,8 +2428,8 @@ btr_attach_half_pages(
{
dtuple_t* node_ptr_upper;
mem_heap_t* heap;
- buf_block_t* prev_block = NULL;
- buf_block_t* next_block = NULL;
+ buf_block_t* prev_block = nullptr;
+ buf_block_t* next_block = nullptr;
buf_block_t* lower_block;
buf_block_t* upper_block;
@@ -2458,9 +2448,12 @@ btr_attach_half_pages(
lower_block = new_block;
upper_block = block;
+ cursor.page_cur.block = block;
+ cursor.page_cur.index = index;
+
/* Look up the index for the node pointer to page */
- offsets = btr_page_get_father_block(NULL, heap, index,
- block, mtr, &cursor);
+ offsets = btr_page_get_father_block(nullptr, heap, mtr,
+ &cursor);
/* Replace the address of the old child node (= page) with the
address of the new lower half */
@@ -2583,12 +2576,12 @@ btr_page_tuple_smaller(
return false;
}
- *offsets = rec_get_offsets(first_rec, cursor->index, *offsets,
+ *offsets = rec_get_offsets(first_rec, cursor->index(), *offsets,
page_is_leaf(block->page.frame)
- ? cursor->index->n_core_fields : 0,
+ ? cursor->index()->n_core_fields : 0,
n_uniq, heap);
- return cmp_dtuple_rec(tuple, first_rec, cursor->index, *offsets) < 0;
+ return cmp_dtuple_rec(tuple, first_rec, cursor->index(), *offsets) < 0;
}
/** Insert the tuple into the right sibling page, if the cursor is at the end
@@ -2619,7 +2612,7 @@ btr_insert_into_right_sibling(
page_t* page = buf_block_get_frame(block);
const uint32_t next_page_no = btr_page_get_next(page);
- ut_ad(mtr->memo_contains_flagged(&cursor->index->lock,
+ ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock,
MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK));
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
ut_ad(heap);
@@ -2638,7 +2631,7 @@ btr_insert_into_right_sibling(
rec_t* rec = nullptr;
ulint max_size;
- next_block = btr_block_get(*cursor->index, next_page_no, RW_X_LATCH,
+ next_block = btr_block_get(*cursor->index(), next_page_no, RW_X_LATCH,
page_is_leaf(page), mtr);
if (UNIV_UNLIKELY(!next_block)) {
return nullptr;
@@ -2646,14 +2639,17 @@ btr_insert_into_right_sibling(
next_page = buf_block_get_frame(next_block);
const bool is_leaf = page_is_leaf(next_page);
- if (!btr_page_get_father(cursor->index, next_block, mtr,
- &next_father_cursor)) {
+ next_page_cursor.index = cursor->index();
+ next_page_cursor.block = next_block;
+ next_father_cursor.page_cur = next_page_cursor;
+
+ if (!btr_page_get_father(mtr, &next_father_cursor)) {
return nullptr;
}
ulint up_match = 0, low_match = 0;
- if (page_cur_search_with_match(next_block, cursor->index, tuple,
+ if (page_cur_search_with_match(tuple,
PAGE_CUR_LE, &up_match, &low_match,
&next_page_cursor, nullptr)) {
return nullptr;
@@ -2662,19 +2658,18 @@ btr_insert_into_right_sibling(
max_size = page_get_max_insert_size_after_reorganize(next_page, 1);
/* Extends gap lock for the next page */
- if (is_leaf && cursor->index->has_locking()) {
+ if (is_leaf && cursor->index()->has_locking()) {
lock_update_node_pointer(block, next_block);
}
- rec = page_cur_tuple_insert(
- &next_page_cursor, tuple, cursor->index, offsets, &heap,
- n_ext, mtr);
+ rec = page_cur_tuple_insert(&next_page_cursor, tuple, offsets, &heap,
+ n_ext, mtr);
if (!rec) {
if (is_leaf
&& next_block->page.zip.ssize
- && !dict_index_is_clust(cursor->index)
- && !cursor->index->table->is_temporary()) {
+ && !dict_index_is_clust(cursor->index())
+ && !cursor->index()->table->is_temporary()) {
/* Reset the IBUF_BITMAP_FREE bits, because
page_cur_tuple_insert() will have attempted page
reorganize before failing. */
@@ -2708,19 +2703,19 @@ btr_insert_into_right_sibling(
}
dtuple_t* node_ptr = dict_index_build_node_ptr(
- cursor->index, rec, next_block->page.id().page_no(),
+ cursor->index(), rec, next_block->page.id().page_no(),
heap, level);
- if (btr_insert_on_non_leaf_level(flags, cursor->index, level + 1,
+ if (btr_insert_on_non_leaf_level(flags, cursor->index(), level + 1,
node_ptr, mtr) != DB_SUCCESS) {
return nullptr;
}
- ut_ad(rec_offs_validate(rec, cursor->index, *offsets));
+ ut_ad(rec_offs_validate(rec, cursor->index(), *offsets));
if (is_leaf
- && !dict_index_is_clust(cursor->index)
- && !cursor->index->table->is_temporary()) {
+ && !dict_index_is_clust(cursor->index())
+ && !cursor->index()->table->is_temporary()) {
/* Update the free bits of the B-tree page in the
insert buffer bitmap. */
@@ -2864,7 +2859,7 @@ btr_page_split_and_insert(
ut_ad(*err == DB_SUCCESS);
ut_ad(dtuple_check_typed(tuple));
- if (cursor->index->is_spatial()) {
+ if (cursor->index()->is_spatial()) {
/* Split rtree page and update parent */
return rtr_page_split_and_insert(flags, cursor, offsets, heap,
tuple, n_ext, mtr, err);
@@ -2873,17 +2868,18 @@ btr_page_split_and_insert(
if (!*heap) {
*heap = mem_heap_create(1024);
}
- n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
+ n_uniq = dict_index_get_n_unique_in_tree(cursor->index());
func_start:
mem_heap_empty(*heap);
*offsets = NULL;
- ut_ad(mtr->memo_contains_flagged(&cursor->index->lock, MTR_MEMO_X_LOCK
+ ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock,
+ MTR_MEMO_X_LOCK
| MTR_MEMO_SX_LOCK));
- ut_ad(!dict_index_is_online_ddl(cursor->index)
+ ut_ad(!dict_index_is_online_ddl(cursor->index())
|| (flags & BTR_CREATE_FLAG)
- || dict_index_is_clust(cursor->index));
- ut_ad(cursor->index->lock.have_u_or_x());
+ || dict_index_is_clust(cursor->index()));
+ ut_ad(cursor->index()->lock.have_u_or_x());
block = btr_cur_get_block(cursor);
page = buf_block_get_frame(block);
@@ -2942,7 +2938,7 @@ func_start:
got_split_rec:
/* 2. Allocate a new page to the index */
const uint16_t page_level = btr_page_get_level(page);
- new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
+ new_block = btr_page_alloc(cursor->index(), hint_page_no, direction,
page_level, mtr, mtr, err);
if (!new_block) {
@@ -2957,13 +2953,13 @@ got_split_rec:
to contain FIL_NULL in FIL_PAGE_PREV at this stage. */
memset_aligned<4>(new_page + FIL_PAGE_PREV, 0, 4);
}
- btr_page_create(new_block, new_page_zip, cursor->index,
+ btr_page_create(new_block, new_page_zip, cursor->index(),
page_level, mtr);
/* Only record the leaf level page splits. */
if (!page_level) {
- cursor->index->stat_defrag_n_page_split ++;
- cursor->index->stat_defrag_modified_counter ++;
- btr_defragment_save_defrag_stats_if_needed(cursor->index);
+ cursor->index()->stat_defrag_n_page_split ++;
+ cursor->index()->stat_defrag_modified_counter ++;
+ btr_defragment_save_defrag_stats_if_needed(cursor->index());
}
/* 3. Calculate the first record on the upper half-page, and the
@@ -2973,12 +2969,13 @@ got_split_rec:
if (split_rec) {
first_rec = move_limit = split_rec;
- *offsets = rec_get_offsets(split_rec, cursor->index, *offsets,
- page_is_leaf(page)
- ? cursor->index->n_core_fields : 0,
+ *offsets = rec_get_offsets(split_rec, cursor->index(),
+ *offsets, page_is_leaf(page)
+ ? cursor->index()->n_core_fields
+ : 0,
n_uniq, heap);
- insert_left = cmp_dtuple_rec(tuple, split_rec, cursor->index,
+ insert_left = cmp_dtuple_rec(tuple, split_rec, cursor->index(),
*offsets) < 0;
if (!insert_left && new_page_zip && n_iterations > 0) {
@@ -3006,9 +3003,9 @@ insert_empty:
ut_ad(!insert_left);
buf = UT_NEW_ARRAY_NOKEY(
byte,
- rec_get_converted_size(cursor->index, tuple, n_ext));
+ rec_get_converted_size(cursor->index(), tuple, n_ext));
- first_rec = rec_convert_dtuple_to_rec(buf, cursor->index,
+ first_rec = rec_convert_dtuple_to_rec(buf, cursor->index(),
tuple, n_ext);
goto insert_move_limit;
}
@@ -3016,7 +3013,7 @@ insert_empty:
/* 4. Do first the modifications in the tree structure */
/* FIXME: write FIL_PAGE_PREV,FIL_PAGE_NEXT in new_block earlier! */
- *err = btr_attach_half_pages(flags, cursor->index, block,
+ *err = btr_attach_half_pages(flags, cursor->index(), block,
first_rec, new_block, direction, mtr);
if (UNIV_UNLIKELY(*err != DB_SUCCESS)) {
@@ -3038,11 +3035,10 @@ insert_empty:
if (!srv_read_only_mode
&& insert_will_fit
&& page_is_leaf(page)
- && !dict_index_is_online_ddl(cursor->index)) {
-
- mtr->memo_release(&cursor->index->lock,
- MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK);
-
+ && !dict_index_is_online_ddl(cursor->index())) {
+#if 0 // FIXME: this used to be a no-op, and may cause trouble if enabled
+ mtr->release(cursor->index()->lock);
+#endif
/* NOTE: We cannot release root block latch here, because it
has segment header and already modified in most of cases.*/
}
@@ -3057,7 +3053,8 @@ insert_empty:
#endif /* UNIV_ZIP_COPY */
|| (*err = page_move_rec_list_start(new_block, block,
move_limit,
- cursor->index, mtr))) {
+ cursor->index(),
+ mtr))) {
if (*err != DB_FAIL) {
return nullptr;
}
@@ -3069,12 +3066,12 @@ insert_empty:
as appropriate. Deleting will always succeed. */
ut_a(new_page_zip);
- page_zip_copy_recs(new_block,
- page_zip, page, cursor->index, mtr);
+ page_zip_copy_recs(new_block, page_zip, page,
+ cursor->index(), mtr);
*err = page_delete_rec_list_end(move_limit
- page + new_page,
new_block,
- cursor->index,
+ cursor->index(),
ULINT_UNDEFINED,
ULINT_UNDEFINED, mtr);
if (*err != DB_SUCCESS) {
@@ -3082,7 +3079,7 @@ insert_empty:
}
/* Update the lock table and possible hash index. */
- if (cursor->index->has_locking()) {
+ if (cursor->index()->has_locking()) {
lock_move_rec_list_start(
new_block, block, move_limit,
new_page + PAGE_NEW_INFIMUM);
@@ -3094,13 +3091,13 @@ insert_empty:
/* Delete the records from the source page. */
page_delete_rec_list_start(move_limit, block,
- cursor->index, mtr);
+ cursor->index(), mtr);
}
left_block = new_block;
right_block = block;
- if (cursor->index->has_locking()) {
+ if (cursor->index()->has_locking()) {
lock_update_split_left(right_block, left_block);
}
} else {
@@ -3112,7 +3109,7 @@ insert_empty:
#endif /* UNIV_ZIP_COPY */
|| (*err = page_move_rec_list_end(new_block, block,
move_limit,
- cursor->index, mtr))) {
+ cursor->index(), mtr))) {
if (*err != DB_FAIL) {
return nullptr;
}
@@ -3124,14 +3121,14 @@ insert_empty:
as appropriate. Deleting will always succeed. */
ut_a(new_page_zip);
- page_zip_copy_recs(new_block,
- page_zip, page, cursor->index, mtr);
+ page_zip_copy_recs(new_block, page_zip, page,
+ cursor->index(), mtr);
page_delete_rec_list_start(move_limit - page
+ new_page, new_block,
- cursor->index, mtr);
+ cursor->index(), mtr);
/* Update the lock table and possible hash index. */
- if (cursor->index->has_locking()) {
+ if (cursor->index()->has_locking()) {
lock_move_rec_list_end(new_block, block,
move_limit);
}
@@ -3142,7 +3139,7 @@ insert_empty:
/* Delete the records from the source page. */
*err = page_delete_rec_list_end(move_limit, block,
- cursor->index,
+ cursor->index(),
ULINT_UNDEFINED,
ULINT_UNDEFINED, mtr);
if (*err != DB_SUCCESS) {
@@ -3153,15 +3150,16 @@ insert_empty:
left_block = block;
right_block = new_block;
- if (cursor->index->has_locking()) {
+ if (cursor->index()->has_locking()) {
lock_update_split_right(right_block, left_block);
}
}
#ifdef UNIV_ZIP_DEBUG
if (page_zip) {
- ut_a(page_zip_validate(page_zip, page, cursor->index));
- ut_a(page_zip_validate(new_page_zip, new_page, cursor->index));
+ ut_a(page_zip_validate(page_zip, page, cursor->index()));
+ ut_a(page_zip_validate(new_page_zip, new_page,
+ cursor->index()));
}
#endif /* UNIV_ZIP_DEBUG */
@@ -3176,17 +3174,18 @@ insert_empty:
/* 7. Reposition the cursor for insert and try insertion */
page_cursor = btr_cur_get_page_cur(cursor);
+ page_cursor->block = insert_block;
ulint up_match = 0, low_match = 0;
- if (page_cur_search_with_match(insert_block, cursor->index, tuple,
+ if (page_cur_search_with_match(tuple,
PAGE_CUR_LE, &up_match, &low_match,
page_cursor, nullptr)) {
*err = DB_CORRUPTION;
return nullptr;
}
- rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
+ rec = page_cur_tuple_insert(page_cursor, tuple,
offsets, heap, n_ext, mtr);
#ifdef UNIV_ZIP_DEBUG
@@ -3216,13 +3215,13 @@ insert_empty:
goto insert_failed;
}
- *err = btr_page_reorganize(page_cursor, cursor->index, mtr);
+ *err = btr_page_reorganize(page_cursor, mtr);
if (*err != DB_SUCCESS) {
return nullptr;
}
- rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
+ rec = page_cur_tuple_insert(page_cursor, tuple,
offsets, heap, n_ext, mtr);
if (rec == NULL) {
@@ -3230,8 +3229,8 @@ insert_empty:
start of the function for a new split */
insert_failed:
/* We play safe and reset the free bits for new_page */
- if (!dict_index_is_clust(cursor->index)
- && !cursor->index->table->is_temporary()) {
+ if (!dict_index_is_clust(page_cursor->index)
+ && !page_cursor->index->table->is_temporary()) {
ibuf_reset_free_bits(new_block);
ibuf_reset_free_bits(block);
}
@@ -3248,8 +3247,8 @@ func_exit:
/* Insert fit on the page: update the free bits for the
left and right pages in the same mtr */
- if (!dict_index_is_clust(cursor->index)
- && !cursor->index->table->is_temporary()
+ if (!dict_index_is_clust(page_cursor->index)
+ && !page_cursor->index->table->is_temporary()
&& page_is_leaf(page)) {
ibuf_update_free_bits_for_two_pages_low(
@@ -3258,10 +3257,12 @@ func_exit:
MONITOR_INC(MONITOR_INDEX_SPLIT);
- ut_ad(page_validate(buf_block_get_frame(left_block), cursor->index));
- ut_ad(page_validate(buf_block_get_frame(right_block), cursor->index));
+ ut_ad(page_validate(buf_block_get_frame(left_block),
+ page_cursor->index));
+ ut_ad(page_validate(buf_block_get_frame(right_block),
+ page_cursor->index));
- ut_ad(!rec || rec_offs_validate(rec, cursor->index, *offsets));
+ ut_ad(!rec || rec_offs_validate(rec, page_cursor->index, *offsets));
return(rec);
}
@@ -3360,14 +3361,14 @@ btr_lift_page_up(
* (REC_OFFS_HEADER_SIZE + 1 + 1
+ unsigned(index->n_fields)));
buf_block_t* b;
+ cursor.page_cur.index = index;
+ cursor.page_cur.block = block;
- if (dict_index_is_spatial(index)) {
+ if (index->is_spatial()) {
offsets = rtr_page_get_father_block(
- NULL, heap, index, block, mtr,
- NULL, &cursor);
+ nullptr, heap, mtr, nullptr, &cursor);
} else {
offsets = btr_page_get_father_block(offsets, heap,
- index, block,
mtr, &cursor);
}
father_block = btr_cur_get_block(&cursor);
@@ -3384,14 +3385,12 @@ btr_lift_page_up(
b->page.id().page_no() != root_page_no; ) {
ut_a(n_blocks < BTR_MAX_LEVELS);
- if (dict_index_is_spatial(index)) {
+ if (index->is_spatial()) {
offsets = rtr_page_get_father_block(
- NULL, heap, index, b, mtr,
- NULL, &cursor);
+ nullptr, heap, mtr, nullptr, &cursor);
} else {
offsets = btr_page_get_father_block(offsets,
heap,
- index, b,
mtr,
&cursor);
}
@@ -3588,10 +3587,12 @@ btr_compress(
page_is_comp(page))));
heap = mem_heap_create(100);
+ father_cursor.page_cur.index = index;
+ father_cursor.page_cur.block = block;
- if (dict_index_is_spatial(index)) {
+ if (index->is_spatial()) {
offsets = rtr_page_get_father_block(
- NULL, heap, index, block, mtr, cursor, &father_cursor);
+ NULL, heap, mtr, cursor, &father_cursor);
ut_ad(cursor->page_cur.block->page.id() == block->page.id());
rec_t* my_rec = father_cursor.page_cur.rec;
@@ -3602,18 +3603,26 @@ btr_compress(
<< page_no << "instead of "
<< block->page.id().page_no();
offsets = btr_page_get_father_block(
- NULL, heap, index, block, mtr, &father_cursor);
+ NULL, heap, mtr, &father_cursor);
}
} else {
offsets = btr_page_get_father_block(
- NULL, heap, index, block, mtr, &father_cursor);
+ NULL, heap, mtr, &father_cursor);
}
if (adjust) {
nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor));
if (UNIV_UNLIKELY(!nth_rec || nth_rec == ULINT_UNDEFINED)) {
+ corrupted:
err = DB_CORRUPTION;
- goto err_exit;
+ err_exit:
+ /* We play it safe and reset the free bits. */
+ if (merge_block && merge_block->zip_size()
+ && page_is_leaf(merge_block->page.frame)
+ && !index->is_clust()) {
+ ibuf_reset_free_bits(merge_block);
+ }
+ goto func_exit;
}
}
@@ -3622,7 +3631,23 @@ btr_compress(
to the father */
merge_block = btr_lift_page_up(index, block, mtr, &err);
- goto func_exit;
+success:
+ if (adjust) {
+ ut_ad(nth_rec > 0);
+ if (rec_t* nth
+ = page_rec_get_nth(merge_block->page.frame,
+ nth_rec)) {
+ btr_cur_position(index, nth,
+ merge_block, cursor);
+ } else {
+ goto corrupted;
+ }
+ }
+
+ MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
+func_exit:
+ mem_heap_free(heap);
+ DBUG_RETURN(err);
}
ut_d(leftmost_child =
@@ -3658,8 +3683,7 @@ cannot_merge:
: FIL_PAGE_PREV),
block->page.frame
+ FIL_PAGE_OFFSET, 4))) {
- err = DB_CORRUPTION;
- goto err_exit;
+ goto corrupted;
}
ut_ad(page_validate(merge_page, index));
@@ -3675,9 +3699,12 @@ cannot_merge:
}
#endif /* UNIV_ZIP_DEBUG */
+ btr_cur_t cursor2;
+ cursor2.page_cur.index = index;
+ cursor2.page_cur.block = merge_block;
+
/* Move records to the merge page */
if (is_left) {
- btr_cur_t cursor2;
rtr_mbr_t new_mbr;
rec_offs* offsets2 = NULL;
@@ -3687,8 +3714,7 @@ cannot_merge:
page */
if (!rtr_check_same_block(
index, &cursor2,
- btr_cur_get_block(&father_cursor),
- merge_block, heap)) {
+ btr_cur_get_block(&father_cursor), heap)) {
is_left = false;
goto retry;
}
@@ -3729,7 +3755,7 @@ cannot_merge:
const page_id_t id{block->page.id()};
- if (dict_index_is_spatial(index)) {
+ if (index->is_spatial()) {
rec_t* my_rec = father_cursor.page_cur.rec;
ulint page_no = btr_node_ptr_get_child_page_no(
@@ -3765,8 +3791,7 @@ cannot_merge:
if (adjust) {
ulint n = page_rec_get_n_recs_before(orig_pred);
if (UNIV_UNLIKELY(!n || n == ULINT_UNDEFINED)) {
- err = DB_CORRUPTION;
- goto err_exit;
+ goto corrupted;
}
nth_rec += n;
}
@@ -3774,22 +3799,16 @@ cannot_merge:
rec_t* orig_succ;
ibool compressed;
dberr_t err;
- btr_cur_t cursor2;
- /* father cursor pointing to node ptr
- of the right sibling */
byte fil_page_prev[4];
- if (dict_index_is_spatial(index)) {
- cursor2.rtr_info = NULL;
-
+ if (index->is_spatial()) {
/* For spatial index, we disallow merge of blocks
with different parents, since the merge would need
to update entry (for MBR and Primary key) in the
parent of block being merged */
if (!rtr_check_same_block(
index, &cursor2,
- btr_cur_get_block(&father_cursor),
- merge_block, heap)) {
+ btr_cur_get_block(&father_cursor), heap)) {
goto cannot_merge;
}
@@ -3797,8 +3816,7 @@ cannot_merge:
necessary in recursive page merge. */
cursor2.rtr_info = cursor->rtr_info;
cursor2.tree_height = cursor->tree_height;
- } else if (!btr_page_get_father(index, merge_block, mtr,
- &cursor2)) {
+ } else if (!btr_page_get_father(mtr, &cursor2)) {
goto cannot_merge;
}
@@ -3816,7 +3834,7 @@ cannot_merge:
orig_succ = page_copy_rec_list_end(merge_block, block,
page_get_infimum_rec(page),
- cursor->index, mtr, &err);
+ cursor->index(), mtr, &err);
if (!orig_succ) {
ut_a(merge_page_zip);
@@ -3985,33 +4003,10 @@ cannot_merge:
if (err == DB_SUCCESS) {
ut_ad(leftmost_child
|| btr_check_node_ptr(index, merge_block, mtr));
-func_exit:
- if (adjust) {
- ut_ad(nth_rec > 0);
- if (rec_t* nth
- = page_rec_get_nth(merge_block->page.frame,
- nth_rec)) {
- btr_cur_position(index, nth,
- merge_block, cursor);
- } else {
- err = DB_CORRUPTION;
- goto err_exit;
- }
- }
-
- MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
+ goto success;
} else {
-err_exit:
- /* We play it safe and reset the free bits. */
- if (merge_block && merge_block->zip_size()
- && page_is_leaf(merge_block->page.frame)
- && !index->is_clust()) {
- ibuf_reset_free_bits(merge_block);
- }
+ goto err_exit;
}
-
- mem_heap_free(heap);
- DBUG_RETURN(err);
}
/*************************************************************//**
@@ -4053,16 +4048,17 @@ btr_discard_only_page_on_level(
ut_ad(block->page.id().space() == index->table->space->id);
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
btr_search_drop_page_hash_index(block);
+ cursor.page_cur.index = index;
+ cursor.page_cur.block = block;
if (index->is_spatial()) {
/* Check any concurrent search having this page */
rtr_check_discard_page(index, NULL, block);
- if (!rtr_page_get_father(index, block, mtr, nullptr,
- &cursor)) {
+ if (!rtr_page_get_father(mtr, nullptr, &cursor)) {
return;
}
} else {
- if (!btr_page_get_father(index, block, mtr, &cursor)) {
+ if (!btr_page_get_father(mtr, &cursor)) {
return;
}
}
@@ -4113,11 +4109,11 @@ btr_discard_only_page_on_level(
if (rec) {
page_cur_t cur;
page_cur_set_before_first(block, &cur);
+ cur.index = index;
DBUG_ASSERT(index->table->instant);
DBUG_ASSERT(rec_is_alter_metadata(rec, *index));
btr_set_instant(block, *index, mtr);
- rec = page_cur_insert_rec_low(&cur, index, rec,
- offsets, mtr);
+ rec = page_cur_insert_rec_low(&cur, rec, offsets, mtr);
ut_ad(rec);
mem_heap_free(heap);
} else if (index->is_instant()) {
@@ -4152,6 +4148,7 @@ btr_discard_page(
block = btr_cur_get_block(cursor);
index = btr_cur_get_index(cursor);
+ parent_cursor.page_cur = cursor->page_cur;
ut_ad(dict_index_get_page(index) != block->page.id().page_no());
@@ -4162,8 +4159,8 @@ btr_discard_page(
MONITOR_INC(MONITOR_INDEX_DISCARD);
if (index->is_spatial()
- ? !rtr_page_get_father(index, block, mtr, cursor, &parent_cursor)
- : !btr_page_get_father(index, block, mtr, &parent_cursor)) {
+ ? !rtr_page_get_father(mtr, cursor, &parent_cursor)
+ : !btr_page_get_father(mtr, &parent_cursor)) {
return DB_CORRUPTION;
}
@@ -4455,14 +4452,16 @@ btr_check_node_ptr(
return(TRUE);
}
+ cursor.page_cur.index = index;
+ cursor.page_cur.block = block;
+
heap = mem_heap_create(256);
if (dict_index_is_spatial(index)) {
- offsets = rtr_page_get_father_block(NULL, heap, index, block, mtr,
+ offsets = rtr_page_get_father_block(NULL, heap, mtr,
NULL, &cursor);
} else {
- offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
- &cursor);
+ offsets = btr_page_get_father_block(NULL, heap, mtr, &cursor);
}
if (page_is_leaf(page)) {
diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc
index 223d903c803..013cd13102c 100644
--- a/storage/innobase/btr/btr0bulk.cc
+++ b/storage/innobase/btr/btr0bulk.cc
@@ -827,7 +827,6 @@ PageBulk::storeExt(
btr_pcur_t btr_pcur;
btr_pcur.pos_state = BTR_PCUR_IS_POSITIONED;
btr_pcur.latch_mode = BTR_MODIFY_LEAF;
- btr_pcur.btr_cur.index = m_index;
btr_pcur.btr_cur.page_cur.index = m_index;
btr_pcur.btr_cur.page_cur.rec = m_cur_rec;
btr_pcur.btr_cur.page_cur.offsets = offsets;
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index edeaab0fff6..b7c7081a247 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -196,7 +196,7 @@ btr_rec_free_externally_stored_fields(
void
btr_cur_latch_leaves(
buf_block_t* block,
- ulint latch_mode,
+ btr_latch_mode latch_mode,
btr_cur_t* cursor,
mtr_t* mtr,
btr_latch_leaves_t* latch_leaves)
@@ -204,15 +204,15 @@ btr_cur_latch_leaves(
compile_time_assert(int(MTR_MEMO_PAGE_S_FIX) == int(RW_S_LATCH));
compile_time_assert(int(MTR_MEMO_PAGE_X_FIX) == int(RW_X_LATCH));
compile_time_assert(int(MTR_MEMO_PAGE_SX_FIX) == int(RW_SX_LATCH));
- ut_ad(block->page.id().space() == cursor->index->table->space->id);
+ ut_ad(block->page.id().space() == cursor->index()->table->space->id);
ut_ad(block->page.in_file());
ut_ad(srv_read_only_mode
- || mtr->memo_contains_flagged(&cursor->index->lock,
+ || mtr->memo_contains_flagged(&cursor->index()->lock,
MTR_MEMO_S_LOCK
| MTR_MEMO_X_LOCK
| MTR_MEMO_SX_LOCK));
auto rtr_info = cursor->rtr_info;
- if (UNIV_LIKELY_NULL(rtr_info) && !cursor->index->is_spatial()) {
+ if (UNIV_LIKELY_NULL(rtr_info) && !cursor->index()->is_spatial()) {
rtr_info = nullptr;
}
@@ -223,6 +223,8 @@ btr_cur_latch_leaves(
static_assert(BTR_SEARCH_LEAF & BTR_SEARCH_TREE, "");
switch (latch_mode) {
+ default:
+ break;
uint32_t left_page_no;
uint32_t right_page_no;
ulint save;
@@ -247,7 +249,7 @@ latch_block:
case BTR_MODIFY_TREE:
/* It is exclusive for other operations which calls
btr_page_set_prev() */
- ut_ad(mtr->memo_contains_flagged(&cursor->index->lock,
+ ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock,
MTR_MEMO_X_LOCK
| MTR_MEMO_SX_LOCK));
save = mtr->get_savepoint();
@@ -256,7 +258,7 @@ latch_block:
if (left_page_no != FIL_NULL) {
buf_block_t *b = btr_block_get(
- *cursor->index, left_page_no, RW_X_LATCH,
+ *cursor->index(), left_page_no, RW_X_LATCH,
true, mtr);
if (latch_leaves) {
@@ -297,7 +299,7 @@ latch_block:
save = mtr->get_savepoint();
buf_block_t* b = btr_block_get(
- *cursor->index, right_page_no, RW_X_LATCH,
+ *cursor->index(), right_page_no, RW_X_LATCH,
true, mtr);
if (latch_leaves) {
latch_leaves->savepoints[2] = save;
@@ -329,7 +331,8 @@ latch_block:
if (left_page_no != FIL_NULL) {
save = mtr->get_savepoint();
cursor->left_block = btr_block_get(
- *cursor->index, left_page_no, mode, true, mtr);
+ *cursor->index(), left_page_no,
+ mode, true, mtr);
if (latch_leaves) {
latch_leaves->savepoints[0] = save;
latch_leaves->blocks[0] = cursor->left_block;
@@ -338,7 +341,7 @@ latch_block:
goto latch_block;
case BTR_CONT_MODIFY_TREE:
- ut_ad(cursor->index->is_spatial());
+ ut_ad(cursor->index()->is_spatial());
return;
}
@@ -392,10 +395,10 @@ unreadable:
/* Relax the assertion in rec_init_offsets(). */
ut_ad(!index->in_instant_init);
ut_d(index->in_instant_init = true);
- err = btr_cur_open_at_index_side(true, index, BTR_SEARCH_LEAF,
- &cur, 0, mtr);
+ err = cur.open_leaf(true, index, BTR_SEARCH_LEAF, mtr);
ut_d(index->in_instant_init = false);
if (err != DB_SUCCESS) {
+ index->table->file_unreadable = true;
index->table->corrupted = true;
return err;
}
@@ -738,7 +741,7 @@ bool
btr_cur_optimistic_latch_leaves(
buf_block_t* block,
ib_uint64_t modify_clock,
- ulint* latch_mode,
+ btr_latch_mode* latch_mode,
btr_cur_t* cursor,
mtr_t* mtr)
{
@@ -754,8 +757,8 @@ btr_cur_optimistic_latch_leaves(
case BTR_MODIFY_LEAF:
return(buf_page_optimistic_get(*latch_mode, block,
modify_clock, mtr));
- case BTR_SEARCH_PREV:
- case BTR_MODIFY_PREV:
+ case BTR_SEARCH_PREV: /* btr_pcur_move_backward_from_page() */
+ case BTR_MODIFY_PREV: /* Ditto, or ibuf_insert() */
uint32_t curr_page_no, left_page_no;
{
transactional_shared_lock_guard<block_lock> g{
@@ -777,18 +780,17 @@ btr_cur_optimistic_latch_leaves(
if (left_page_no != FIL_NULL) {
cursor->left_block = buf_page_get_gen(
- page_id_t(cursor->index->table->space_id,
+ page_id_t(cursor->index()->table->space_id,
left_page_no),
- cursor->index->table->space->zip_size(),
+ cursor->index()->table->space->zip_size(),
mode, nullptr, BUF_GET_POSSIBLY_FREED, mtr);
if (cursor->left_block
&& btr_page_get_next(
cursor->left_block->page.frame)
!= curr_page_no) {
- /* release the left block */
- btr_leaf_page_release(
- cursor->left_block, mode, mtr);
+release_left_block:
+ mtr->release_last_page();
return false;
}
} else {
@@ -803,19 +805,16 @@ btr_cur_optimistic_latch_leaves(
buf_page_optimistic_get() buffer-fixes
it again. */
ut_ad(2 <= block->page.buf_fix_count());
- *latch_mode = mode;
+ *latch_mode = btr_latch_mode(mode);
return(true);
- } else {
- /* release the block and decrement of
- buf_fix_count which was incremented
- in buf_page_optimistic_get() */
- btr_leaf_page_release(block, mode, mtr);
}
+
+ mtr->release_last_page();
}
ut_ad(block->page.buf_fix_count());
if (cursor->left_block) {
- btr_leaf_page_release(cursor->left_block, mode, mtr);
+ goto release_left_block;
}
}
@@ -828,9 +827,7 @@ at the latch_mode.
@param latch_mode in/out: pointer to latch_mode
@return intention for latching tree */
static
-btr_intention_t
-btr_cur_get_and_clear_intention(
- ulint *latch_mode)
+btr_intention_t btr_cur_get_and_clear_intention(btr_latch_mode *latch_mode)
{
btr_intention_t intention;
@@ -845,7 +842,8 @@ btr_cur_get_and_clear_intention(
/* both or unknown */
intention = BTR_INTENTION_BOTH;
}
- *latch_mode &= ulint(~(BTR_LATCH_FOR_INSERT | BTR_LATCH_FOR_DELETE));
+ *latch_mode = btr_latch_mode(
+ *latch_mode & ~(BTR_LATCH_FOR_INSERT | BTR_LATCH_FOR_DELETE));
return(intention);
}
@@ -1211,7 +1209,6 @@ If mode is PAGE_CUR_LE , cursor is left at the place where an insert of the
search tuple should be performed in the B-tree. InnoDB does an insert
immediately after the cursor. Thus, the cursor may end up on a user record,
or on a page infimum record.
-@param index index
@param level the tree level of search
@param tuple data tuple; NOTE: n_fields_cmp in tuple must be set so that
it cannot get compared to the node ptr page number field!
@@ -1230,9 +1227,10 @@ or on a page infimum record.
@param autoinc PAGE_ROOT_AUTO_INC to be written (0 if none)
@return DB_SUCCESS on success or error code otherwise */
TRANSACTIONAL_TARGET
-dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
+dberr_t btr_cur_search_to_nth_level(ulint level,
const dtuple_t *tuple,
- page_cur_mode_t mode, ulint latch_mode,
+ page_cur_mode_t mode,
+ btr_latch_mode latch_mode,
btr_cur_t *cursor, mtr_t *mtr,
ib_uint64_t autoinc)
{
@@ -1254,7 +1252,6 @@ dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
ulint root_height = 0; /* remove warning */
btr_intention_t lock_intention;
- bool modify_external;
buf_block_t* tree_blocks[BTR_MAX_LEVELS];
ulint tree_savepoints[BTR_MAX_LEVELS];
ulint n_blocks = 0;
@@ -1270,6 +1267,7 @@ dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
bool rtree_parent_modified = false;
bool mbr_adj = false;
bool found = false;
+ dict_index_t * const index = cursor->index();
DBUG_ENTER("btr_cur_search_to_nth_level");
@@ -1303,11 +1301,9 @@ dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
cursor->low_match = ULINT_UNDEFINED;
#endif /* UNIV_DEBUG */
- ibool s_latch_by_caller;
-
- s_latch_by_caller = latch_mode & BTR_ALREADY_S_LATCHED;
+ const bool latch_by_caller = latch_mode & BTR_ALREADY_S_LATCHED;
- ut_ad(!s_latch_by_caller
+ ut_ad(!latch_by_caller
|| srv_read_only_mode
|| mtr->memo_contains_flagged(&index->lock, MTR_MEMO_S_LOCK
| MTR_MEMO_SX_LOCK));
@@ -1344,14 +1340,10 @@ dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
lock_intention = btr_cur_get_and_clear_intention(&latch_mode);
- modify_external = latch_mode & BTR_MODIFY_EXTERNAL;
-
/* Turn the flags unrelated to the latch mode off. */
latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
- ut_ad(!modify_external || latch_mode == BTR_MODIFY_LEAF);
-
- ut_ad(!s_latch_by_caller
+ ut_ad(!latch_by_caller
|| latch_mode == BTR_SEARCH_LEAF
|| latch_mode == BTR_SEARCH_TREE
|| latch_mode == BTR_MODIFY_LEAF);
@@ -1363,7 +1355,6 @@ dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
ut_ad(autoinc == 0 || level == 0);
cursor->flag = BTR_CUR_BINARY;
- cursor->index = index;
#ifndef BTR_CUR_ADAPT
guess = NULL;
@@ -1381,7 +1372,6 @@ dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
if (!btr_search_enabled) {
} else if (autoinc == 0
&& latch_mode <= BTR_MODIFY_LEAF
- && !modify_external
# ifdef PAGE_CUR_LE_OR_EXTENDS
&& mode != PAGE_CUR_LE_OR_EXTENDS
# endif /* PAGE_CUR_LE_OR_EXTENDS */
@@ -1463,16 +1453,9 @@ x_latch_index:
break;
default:
if (!srv_read_only_mode) {
- if (s_latch_by_caller) {
- } else if (!modify_external) {
- /* BTR_SEARCH_TREE is intended to be used with
- BTR_ALREADY_S_LATCHED */
+ if (!latch_by_caller) {
ut_ad(latch_mode != BTR_SEARCH_TREE);
-
mtr_s_lock_index(index, mtr);
- } else {
- /* BTR_MODIFY_EXTERNAL needs to be excluded */
- mtr_sx_lock_index(index, mtr);
}
upper_rw_latch = RW_S_LATCH;
} else {
@@ -1483,6 +1466,7 @@ x_latch_index:
latch_mode);
page_cursor = btr_cur_get_page_cur(cursor);
+ page_cursor->index = index;
const ulint zip_size = index->table->space->zip_size();
@@ -1540,10 +1524,9 @@ search_loop:
each pages should be latched before reading. */
if (height == ULINT_UNDEFINED
&& upper_rw_latch == RW_S_LATCH
- && (modify_external || autoinc)) {
+ && autoinc) {
/* needs sx-latch of root page
- for fseg operation or for writing
- PAGE_ROOT_AUTO_INC */
+ for writing PAGE_ROOT_AUTO_INC */
rw_latch = RW_SX_LATCH;
} else {
rw_latch = upper_rw_latch;
@@ -1571,8 +1554,6 @@ retry_page_get:
block = buf_page_get_gen(page_id, zip_size, rw_latch, guess,
buf_mode, mtr, &err,
height == 0 && !index->is_clust());
- tree_blocks[n_blocks] = block;
-
if (!block) {
switch (err) {
case DB_SUCCESS:
@@ -1657,10 +1638,10 @@ retry_page_get:
goto retry_page_get;
}
+ tree_blocks[n_blocks] = block;
+
if (height && prev_tree_blocks) {
/* also latch left sibling */
- buf_block_t* get_block;
-
ut_ad(rw_latch == RW_NO_LATCH);
rw_latch = upper_rw_latch;
@@ -1675,43 +1656,25 @@ retry_page_get:
prev_tree_savepoints[prev_n_blocks]
= mtr_set_savepoint(mtr);
- get_block = buf_page_get_gen(
+ buf_block_t* get_block = buf_page_get_gen(
page_id_t(page_id.space(), left_page_no),
zip_size, rw_latch, NULL, buf_mode,
mtr, &err);
- prev_tree_blocks[prev_n_blocks] = get_block;
- prev_n_blocks++;
-
if (!get_block) {
if (err == DB_DECRYPTION_FAILED) {
btr_decryption_failed(*index);
}
-
goto func_exit;
}
+ prev_tree_blocks[prev_n_blocks++] = get_block;
/* BTR_MODIFY_TREE doesn't update prev/next_page_no,
without their parent page's lock. So, not needed to
retry here, because we have the parent page's lock. */
}
- /* release RW_NO_LATCH page and lock with RW_S_LATCH */
- mtr_release_block_at_savepoint(
- mtr, tree_savepoints[n_blocks],
- tree_blocks[n_blocks]);
-
- tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
- block = buf_page_get_gen(page_id, zip_size,
- rw_latch, NULL, buf_mode, mtr, &err);
- tree_blocks[n_blocks] = block;
-
- if (!block) {
- if (err == DB_DECRYPTION_FAILED) {
- btr_decryption_failed(*index);
- }
-
- goto func_exit;
- }
+ mtr->s_lock_register(tree_savepoints[n_blocks]);
+ block->page.lock.s_lock();
}
page = buf_block_get_frame(block);
@@ -1725,7 +1688,7 @@ retry_page_get:
is latched differently from leaf pages. */
ut_ad(root_leaf_rw_latch != RW_NO_LATCH);
ut_ad(rw_latch == RW_S_LATCH || rw_latch == RW_SX_LATCH);
- ut_ad(rw_latch == RW_S_LATCH || modify_external || autoinc);
+ ut_ad(rw_latch == RW_S_LATCH || autoinc);
ut_ad(!autoinc || root_leaf_rw_latch == RW_X_LATCH);
ut_ad(n_blocks == 0);
@@ -1787,12 +1750,9 @@ retry_page_get:
case BTR_CONT_SEARCH_TREE:
break;
default:
- if (!s_latch_by_caller
- && !srv_read_only_mode
- && !modify_external) {
+ if (!latch_by_caller
+ && !srv_read_only_mode) {
/* Release the tree s-latch */
- /* NOTE: BTR_MODIFY_EXTERNAL
- needs to keep tree sx-latch */
mtr_release_s_latch_at_savepoint(
mtr, savepoint,
&index->lock);
@@ -1815,7 +1775,7 @@ retry_page_get:
for (; n_releases < n_blocks; n_releases++) {
if (n_releases == 0
- && (modify_external || autoinc)) {
+ && (autoinc)) {
/* keep the root page latch */
ut_ad(mtr->memo_contains_flagged(
tree_blocks[n_releases],
@@ -1880,6 +1840,8 @@ retry_page_get:
}
}
+ page_cursor->block = block;
+
if (dict_index_is_spatial(index) && page_mode >= PAGE_CUR_CONTAIN) {
ut_ad(need_path);
found = rtr_cur_search_with_match(
@@ -1916,7 +1878,7 @@ retry_page_get:
We only need the byte prefix comparison for the purpose
of updating the adaptive hash index. */
if (page_cur_search_with_match_bytes(
- block, index, tuple, page_mode, &up_match, &up_bytes,
+ tuple, page_mode, &up_match, &up_bytes,
&low_match, &low_bytes, page_cursor)) {
err = DB_CORRUPTION;
goto func_exit;
@@ -1926,7 +1888,7 @@ retry_page_get:
/* Search for complete index fields. */
up_bytes = low_bytes = 0;
if (page_cur_search_with_match(
- block, index, tuple, page_mode, &up_match,
+ tuple, page_mode, &up_match,
&low_match, page_cursor,
need_path ? cursor->rtr_info : nullptr)) {
err = DB_CORRUPTION;
@@ -2175,15 +2137,15 @@ need_opposite_intention:
/* we should sx-latch root page, if released already.
It contains seg_header. */
if (n_releases > 0) {
- mtr_block_sx_latch_at_savepoint(
- mtr, tree_savepoints[0],
+ mtr->sx_latch_at_savepoint(
+ tree_savepoints[0],
tree_blocks[0]);
}
/* x-latch the branch blocks not released yet. */
for (ulint i = n_releases; i <= n_blocks; i++) {
- mtr_block_x_latch_at_savepoint(
- mtr, tree_savepoints[i],
+ mtr->x_latch_at_savepoint(
+ tree_savepoints[i],
tree_blocks[i]);
}
}
@@ -2247,8 +2209,9 @@ need_opposite_intention:
? cursor->rtr_info : NULL;
for (ulint i = 0; i < n_blocks; i++) {
+ page_cursor->block = tree_blocks[i];
if (page_cur_search_with_match(
- tree_blocks[i], index, tuple,
+ tuple,
page_mode, &up_match,
&low_match, page_cursor,
rtr_info)) {
@@ -2353,7 +2316,7 @@ need_opposite_intention:
ut_ad(mtr->memo_contains_flagged(block,
upper_rw_latch));
- if (s_latch_by_caller) {
+ if (latch_by_caller) {
ut_ad(latch_mode == BTR_SEARCH_TREE);
/* to exclude modifying tree operations
should sx-latch the index. */
@@ -2445,336 +2408,223 @@ func_exit:
DBUG_RETURN(err);
}
-/*****************************************************************//**
-Opens a cursor at either end of an index. */
-dberr_t
-btr_cur_open_at_index_side(
- bool from_left, /*!< in: true if open to the low end,
- false if to the high end */
- dict_index_t* index, /*!< in: index */
- ulint latch_mode, /*!< in: latch mode */
- btr_cur_t* cursor, /*!< in/out: cursor */
- ulint level, /*!< in: level to search for
- (0=leaf). */
- mtr_t* mtr) /*!< in/out: mini-transaction */
+dberr_t btr_cur_t::open_leaf(bool first, dict_index_t *index,
+ btr_latch_mode latch_mode, mtr_t *mtr)
{
- page_cur_t* page_cursor;
- ulint node_ptr_max_size = srv_page_size / 2;
- ulint height;
- rec_t* node_ptr;
- btr_intention_t lock_intention;
- buf_block_t* tree_blocks[BTR_MAX_LEVELS];
- ulint tree_savepoints[BTR_MAX_LEVELS];
- ulint n_blocks = 0;
- ulint n_releases = 0;
- mem_heap_t* heap = NULL;
- rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
- rec_offs* offsets = offsets_;
- dberr_t err;
-
- rec_offs_init(offsets_);
-
- ut_ad(level != ULINT_UNDEFINED);
-
- bool s_latch_by_caller;
-
- s_latch_by_caller = latch_mode & BTR_ALREADY_S_LATCHED;
- latch_mode &= ulint(~BTR_ALREADY_S_LATCHED);
-
- lock_intention = btr_cur_get_and_clear_intention(&latch_mode);
-
- ut_ad(!(latch_mode & BTR_MODIFY_EXTERNAL));
-
- /* This function doesn't need to lock left page of the leaf page */
- if (latch_mode == BTR_SEARCH_PREV) {
- latch_mode = BTR_SEARCH_LEAF;
- } else if (latch_mode == BTR_MODIFY_PREV) {
- latch_mode = BTR_MODIFY_LEAF;
- }
-
- /* Store the position of the tree latch we push to mtr so that we
- know how to release it when we have latched the leaf node */
-
- ulint savepoint = mtr_set_savepoint(mtr);
-
- rw_lock_type_t upper_rw_latch;
-
- switch (latch_mode) {
- case BTR_CONT_MODIFY_TREE:
- case BTR_CONT_SEARCH_TREE:
- upper_rw_latch = RW_NO_LATCH;
- break;
- case BTR_MODIFY_TREE:
- /* Most of delete-intended operations are purging.
- Free blocks and read IO bandwidth should be prior
- for them, when the history list is glowing huge. */
- if (lock_intention == BTR_INTENTION_DELETE
- && buf_pool.n_pend_reads
- && trx_sys.history_size_approx()
- > BTR_CUR_FINE_HISTORY_LENGTH) {
- mtr_x_lock_index(index, mtr);
- } else {
- mtr_sx_lock_index(index, mtr);
- }
- upper_rw_latch = RW_X_LATCH;
- break;
- default:
- ut_ad(!s_latch_by_caller
- || mtr->memo_contains_flagged(&index->lock,
- MTR_MEMO_SX_LOCK
- | MTR_MEMO_S_LOCK));
- if (!srv_read_only_mode) {
- if (!s_latch_by_caller) {
- /* BTR_SEARCH_TREE is intended to be used with
- BTR_ALREADY_S_LATCHED */
- ut_ad(latch_mode != BTR_SEARCH_TREE);
-
- mtr_s_lock_index(index, mtr);
- }
- upper_rw_latch = RW_S_LATCH;
- } else {
- upper_rw_latch = RW_NO_LATCH;
- }
- }
-
- const rw_lock_type_t root_leaf_rw_latch = btr_cur_latch_for_root_leaf(
- latch_mode);
-
- page_cursor = btr_cur_get_page_cur(cursor);
- cursor->index = index;
-
- page_id_t page_id(index->table->space_id, index->page);
- const ulint zip_size = index->table->space->zip_size();
-
- if (root_leaf_rw_latch == RW_X_LATCH) {
- node_ptr_max_size = btr_node_ptr_max_size(index);
- }
-
- height = ULINT_UNDEFINED;
-
- for (;;) {
- ut_ad(n_blocks < BTR_MAX_LEVELS);
- tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
-
- const ulint rw_latch = height
- && (latch_mode != BTR_MODIFY_TREE || height == level)
- ? upper_rw_latch : RW_NO_LATCH;
- buf_block_t* block = buf_page_get_gen(page_id, zip_size,
- rw_latch, NULL, BUF_GET,
- mtr, &err,
- height == 0
- && !index->is_clust());
- ut_ad((block != NULL) == (err == DB_SUCCESS));
- tree_blocks[n_blocks] = block;
-
- if (!block) {
- if (err == DB_DECRYPTION_FAILED) {
- btr_decryption_failed(*index);
- }
-
- goto exit_loop;
- }
-
- const page_t* page = buf_block_get_frame(block);
-
- if (height == ULINT_UNDEFINED
- && page_is_leaf(page)
- && rw_latch != RW_NO_LATCH
- && rw_latch != root_leaf_rw_latch) {
- /* We should retry to get the page, because the root page
- is latched with different level as a leaf page. */
- ut_ad(root_leaf_rw_latch != RW_NO_LATCH);
- ut_ad(rw_latch == RW_S_LATCH);
-
- ut_ad(n_blocks == 0);
- mtr_release_block_at_savepoint(
- mtr, tree_savepoints[n_blocks],
- tree_blocks[n_blocks]);
-
- upper_rw_latch = root_leaf_rw_latch;
- continue;
- }
-
- ut_ad(fil_page_index_page_check(page));
- ut_ad(index->id == btr_page_get_index_id(page));
+ ulint node_ptr_max_size= srv_page_size / 2;
+ btr_intention_t lock_intention;
+ ulint n_blocks= 0;
+ mem_heap_t *heap= nullptr;
+ rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_offs *offsets= offsets_;
+ dberr_t err;
- if (height == ULINT_UNDEFINED) {
- /* We are in the root node */
+ rec_offs_init(offsets_);
- height = btr_page_get_level(page);
- ut_a(height >= level);
- } else {
- /* TODO: flag the index corrupted if this fails */
- ut_ad(height == btr_page_get_level(page));
- }
+ const bool latch_by_caller= latch_mode & BTR_ALREADY_S_LATCHED;
+ latch_mode = btr_latch_mode(latch_mode & ~BTR_ALREADY_S_LATCHED);
- if (height == 0) {
- if (rw_latch == RW_NO_LATCH) {
- btr_cur_latch_leaves(block, latch_mode,
- cursor, mtr);
- }
+ lock_intention= btr_cur_get_and_clear_intention(&latch_mode);
- /* In versions <= 3.23.52 we had forgotten to
- release the tree latch here. If in an index
- scan we had to scan far to find a record
- visible to the current transaction, that could
- starve others waiting for the tree latch. */
+ /* This function doesn't need to lock left page of the leaf page */
+ if (latch_mode == BTR_SEARCH_PREV)
+ latch_mode= BTR_SEARCH_LEAF;
+ else if (latch_mode == BTR_MODIFY_PREV)
+ latch_mode= BTR_MODIFY_LEAF;
- switch (latch_mode) {
- case BTR_MODIFY_TREE:
- case BTR_CONT_MODIFY_TREE:
- case BTR_CONT_SEARCH_TREE:
- break;
- default:
- if (UNIV_UNLIKELY(srv_read_only_mode)) {
- break;
- }
- if (!s_latch_by_caller) {
- /* Release the tree s-latch */
- mtr_release_s_latch_at_savepoint(
- mtr, savepoint, &index->lock);
- }
+ /* Store the position of the tree latch we push to mtr so that we
+ know how to release it when we have latched the leaf node */
+
+ auto savepoint= mtr->get_savepoint();
+
+ rw_lock_type_t upper_rw_latch= RW_X_LATCH;
+
+ switch (latch_mode) {
+ case BTR_CONT_MODIFY_TREE:
+ case BTR_CONT_SEARCH_TREE:
+ abort();
+ break;
+ case BTR_MODIFY_TREE:
+ /* Most of delete-intended operations are purging. Free blocks
+ and read IO bandwidth should be prioritized for them, when the
+ history list is growing huge. */
+ savepoint++;
+ if (lock_intention == BTR_INTENTION_DELETE
+ && buf_pool.n_pend_reads
+ && trx_sys.history_size_approx() > BTR_CUR_FINE_HISTORY_LENGTH)
+ mtr_x_lock_index(index, mtr);
+ else
+ mtr_sx_lock_index(index, mtr);
+ break;
+ default:
+ ut_ad(!latch_by_caller ||
+ mtr->memo_contains_flagged(&index->lock,
+ MTR_MEMO_SX_LOCK | MTR_MEMO_S_LOCK));
+ upper_rw_latch= RW_S_LATCH;
+ if (latch_by_caller)
+ break;
+ ut_ad(latch_mode != BTR_SEARCH_TREE);
+ savepoint++;
+ mtr_s_lock_index(index, mtr);
+ }
- /* release upper blocks */
- for (; n_releases < n_blocks; n_releases++) {
- mtr_release_block_at_savepoint(
- mtr,
- tree_savepoints[n_releases],
- tree_blocks[n_releases]);
- }
- }
- } else if (height == level /* height != 0 */
- && UNIV_LIKELY(!srv_read_only_mode)) {
- /* We already have the block latched. */
- ut_ad(latch_mode == BTR_SEARCH_TREE);
- ut_ad(s_latch_by_caller);
- ut_ad(upper_rw_latch == RW_S_LATCH);
- ut_ad(mtr->memo_contains_flagged(block,
- MTR_MEMO_PAGE_S_FIX));
+ ut_ad(savepoint == mtr->get_savepoint());
- if (s_latch_by_caller) {
- /* to exclude modifying tree operations
- should sx-latch the index. */
- ut_ad(mtr->memo_contains(index->lock,
- MTR_MEMO_SX_LOCK));
- /* because has sx-latch of index,
- can release upper blocks. */
- for (; n_releases < n_blocks; n_releases++) {
- mtr_release_block_at_savepoint(
- mtr,
- tree_savepoints[n_releases],
- tree_blocks[n_releases]);
- }
- }
- }
+ const rw_lock_type_t root_leaf_rw_latch=
+ btr_cur_latch_for_root_leaf(latch_mode);
- if (from_left) {
- page_cur_set_before_first(block, page_cursor);
- } else {
- page_cur_set_after_last(block, page_cursor);
- }
+ page_cur.index = index;
- if (height == level) {
- break;
- }
+ uint32_t page= index->page;
+ const auto zip_size= index->table->space->zip_size();
- ut_ad(height > 0);
+ if (root_leaf_rw_latch == RW_X_LATCH)
+ node_ptr_max_size= btr_node_ptr_max_size(index);
- if (from_left
- ? !page_cur_move_to_next(page_cursor)
- : !page_cur_move_to_prev(page_cursor)) {
- err = DB_CORRUPTION;
- goto exit_loop;
- }
+ for (ulint height= ULINT_UNDEFINED;;)
+ {
+ ut_ad(n_blocks < BTR_MAX_LEVELS);
+ ut_ad(savepoint + n_blocks == mtr->get_savepoint());
- height--;
+ const rw_lock_type_t rw_latch= height && latch_mode != BTR_MODIFY_TREE
+ ? upper_rw_latch
+ : RW_NO_LATCH;
+ buf_block_t* block=
+ btr_block_get(*index, page, rw_latch, !height && !index->is_clust(), mtr,
+ &err);
- node_ptr = page_cur_get_rec(page_cursor);
- offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
- 0, ULINT_UNDEFINED, &heap);
+ ut_ad(!block == (err != DB_SUCCESS));
- /* If the rec is the first or last in the page for
- pessimistic delete intention, it might cause node_ptr insert
- for the upper level. We should change the intention and retry.
- */
- if (latch_mode == BTR_MODIFY_TREE
- && btr_cur_need_opposite_intention(
- page, lock_intention, node_ptr)) {
+ if (!block)
+ {
+ if (err == DB_DECRYPTION_FAILED)
+ btr_decryption_failed(*index);
+ break;
+ }
- ut_ad(upper_rw_latch == RW_X_LATCH);
- /* release all blocks */
- for (; n_releases <= n_blocks; n_releases++) {
- mtr_release_block_at_savepoint(
- mtr, tree_savepoints[n_releases],
- tree_blocks[n_releases]);
- }
+ if (first)
+ page_cur_set_before_first(block, &page_cur);
+ else
+ page_cur_set_after_last(block, &page_cur);
- lock_intention = BTR_INTENTION_BOTH;
+ const uint32_t l= btr_page_get_level(block->page.frame);
- page_id.set_page_no(dict_index_get_page(index));
+ if (height == ULINT_UNDEFINED)
+ {
+ /* We are in the root node */
+ height= l;
+ if (height);
+ else if (upper_rw_latch != root_leaf_rw_latch)
+ {
+ /* We should retry to get the page, because the root page
+ is latched with different level as a leaf page. */
+ ut_ad(n_blocks == 0);
+ ut_ad(root_leaf_rw_latch != RW_NO_LATCH);
+ upper_rw_latch= root_leaf_rw_latch;
+ mtr->rollback_to_savepoint(savepoint);
+ continue;
+ }
+ else
+ {
+ reached_leaf:
+ const auto leaf_savepoint= mtr->get_savepoint();
+ ut_ad(leaf_savepoint);
- height = ULINT_UNDEFINED;
+ if (rw_latch == RW_NO_LATCH)
+ btr_cur_latch_leaves(block, latch_mode, this, mtr);
- n_blocks = 0;
- n_releases = 0;
+ switch (latch_mode) {
+ case BTR_MODIFY_TREE:
+ case BTR_CONT_MODIFY_TREE:
+ case BTR_CONT_SEARCH_TREE:
+ break;
+ default:
+ /* Release index->lock if needed, and the non-leaf pages. */
+ mtr->rollback_to_savepoint(savepoint - !latch_by_caller,
+ leaf_savepoint - 1);
+ }
+ break;
+ }
+ }
+ else if (UNIV_UNLIKELY(height != l))
+ {
+ corrupted:
+ err= DB_CORRUPTION;
+ break;
+ }
- continue;
- }
+ if (!height)
+ goto reached_leaf;
- if (latch_mode == BTR_MODIFY_TREE
- && !btr_cur_will_modify_tree(
- cursor->index, page, lock_intention, node_ptr,
- node_ptr_max_size, zip_size, mtr)) {
- ut_ad(upper_rw_latch == RW_X_LATCH);
- ut_ad(n_releases <= n_blocks);
+ height--;
- /* we can release upper blocks */
- for (; n_releases < n_blocks; n_releases++) {
- if (n_releases == 0) {
- /* we should not release root page
- to pin to same block. */
- continue;
- }
+ if (first
+ ? !page_cur_move_to_next(&page_cur)
+ : !page_cur_move_to_prev(&page_cur))
+ goto corrupted;
- /* release unused blocks to unpin */
- mtr_release_block_at_savepoint(
- mtr, tree_savepoints[n_releases],
- tree_blocks[n_releases]);
- }
- }
+ const rec_t *node_ptr= page_cur.rec;
+ offsets= rec_get_offsets(node_ptr, index, offsets, 0, ULINT_UNDEFINED,
+ &heap);
- if (height == level
- && latch_mode == BTR_MODIFY_TREE) {
- ut_ad(upper_rw_latch == RW_X_LATCH);
- /* we should sx-latch root page, if released already.
- It contains seg_header. */
- if (n_releases > 0) {
- mtr_block_sx_latch_at_savepoint(
- mtr, tree_savepoints[0],
- tree_blocks[0]);
- }
+ ut_ad(latch_mode != BTR_MODIFY_TREE || upper_rw_latch == RW_X_LATCH);
- /* x-latch the branch blocks not released yet. */
- for (ulint i = n_releases; i <= n_blocks; i++) {
- mtr_block_x_latch_at_savepoint(
- mtr, tree_savepoints[i],
- tree_blocks[i]);
- }
- }
+ if (latch_mode != BTR_MODIFY_TREE);
+ else if (btr_cur_need_opposite_intention(block->page.frame,
+ lock_intention, node_ptr))
+ {
+ /* If the rec is the first or last in the page for pessimistic
+ delete intention, it might cause node_ptr insert for the upper
+ level. We should change the intention and retry. */
+
+ mtr->rollback_to_savepoint(savepoint);
+ lock_intention= BTR_INTENTION_BOTH;
+ page= index->page;
+ height= ULINT_UNDEFINED;
+ n_blocks= 0;
+ continue;
+ }
+ else
+ {
+ if (!btr_cur_will_modify_tree(index, block->page.frame,
+ lock_intention, node_ptr,
+ node_ptr_max_size, zip_size, mtr))
+ {
+ ut_ad(n_blocks);
+ /* release buffer-fixes on pages that will not be modified
+ (except the root) */
+ if (n_blocks > 1)
+ {
+ mtr->rollback_to_savepoint(savepoint + 1, savepoint + n_blocks - 1);
+ n_blocks= 1;
+ }
+ }
- /* Go to the child node */
- page_id.set_page_no(
- btr_node_ptr_get_child_page_no(node_ptr, offsets));
+ if (!height)
+ {
+ if (page == index->page)
+ mtr->upgrade_buffer_fix(savepoint, RW_X_LATCH);
+ else
+ {
+ /* The U-latch protects BTR_SEG_HEAP, BTR_SEG_TOP. */
+ mtr->upgrade_buffer_fix(savepoint, RW_SX_LATCH);
+
+ /* Upgrade buffer-fix to exclusive latches on all remaining pages. */
+ for (ulint i= 1; i <= n_blocks; i++)
+ mtr->upgrade_buffer_fix(savepoint + i, RW_X_LATCH);
+ }
+ }
+ }
- n_blocks++;
- }
+ /* Go to the child node */
+ page= btr_node_ptr_get_child_page_no(node_ptr, offsets);
+ n_blocks++;
+ }
- exit_loop:
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
+ if (UNIV_LIKELY_NULL(heap))
+ mem_heap_free(heap);
- return err;
+ return err;
}
/**********************************************************************//**
@@ -2784,7 +2634,7 @@ if the index is unavailable */
bool
btr_cur_open_at_rnd_pos(
dict_index_t* index, /*!< in: index */
- ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
+ btr_latch_mode latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
btr_cur_t* cursor, /*!< in/out: B-tree cursor */
mtr_t* mtr) /*!< in: mtr */
{
@@ -2806,8 +2656,6 @@ btr_cur_open_at_rnd_pos(
lock_intention = btr_cur_get_and_clear_intention(&latch_mode);
- ut_ad(!(latch_mode & BTR_MODIFY_EXTERNAL));
-
ulint savepoint = mtr_set_savepoint(mtr);
rw_lock_type_t upper_rw_latch;
@@ -2862,7 +2710,7 @@ btr_cur_open_at_rnd_pos(
latch_mode);
page_cursor = btr_cur_get_page_cur(cursor);
- cursor->index = index;
+ page_cursor->index = index;
page_id_t page_id(index->table->space_id, index->page);
const ulint zip_size = index->table->space->zip_size();
@@ -2936,7 +2784,7 @@ btr_cur_open_at_rnd_pos(
mtr);
}
- /* btr_cur_open_at_index_side() and
+ /* btr_cur_t::open_leaf() and
btr_cur_search_to_nth_level() release
tree s-latch here.*/
switch (latch_mode) {
@@ -2962,7 +2810,8 @@ btr_cur_open_at_rnd_pos(
}
}
- page_cur_open_on_rnd_user_rec(block, page_cursor);
+ page_cursor->block = block;
+ page_cur_open_on_rnd_user_rec(page_cursor);
if (height == 0) {
@@ -2974,8 +2823,8 @@ btr_cur_open_at_rnd_pos(
height--;
node_ptr = page_cur_get_rec(page_cursor);
- offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
- 0, ULINT_UNDEFINED, &heap);
+ offsets = rec_get_offsets(node_ptr, page_cursor->index,
+ offsets, 0, ULINT_UNDEFINED, &heap);
/* If the rec is the first or last in the page for
pessimistic delete intention, it might cause node_ptr insert
@@ -3007,8 +2856,8 @@ btr_cur_open_at_rnd_pos(
if (latch_mode == BTR_MODIFY_TREE
&& !btr_cur_will_modify_tree(
- cursor->index, page, lock_intention, node_ptr,
- node_ptr_max_size, zip_size, mtr)) {
+ page_cursor->index, page, lock_intention,
+ node_ptr, node_ptr_max_size, zip_size, mtr)) {
ut_ad(upper_rw_latch == RW_X_LATCH);
ut_ad(n_releases <= n_blocks);
@@ -3033,15 +2882,15 @@ btr_cur_open_at_rnd_pos(
/* we should sx-latch root page, if released already.
It contains seg_header. */
if (n_releases > 0) {
- mtr_block_sx_latch_at_savepoint(
- mtr, tree_savepoints[0],
+ mtr->sx_latch_at_savepoint(
+ tree_savepoints[0],
tree_blocks[0]);
}
/* x-latch the branch blocks not released yet. */
for (ulint i = n_releases; i <= n_blocks; i++) {
- mtr_block_x_latch_at_savepoint(
- mtr, tree_savepoints[i],
+ mtr->x_latch_at_savepoint(
+ tree_savepoints[i],
tree_blocks[i]);
}
}
@@ -3097,21 +2946,19 @@ btr_cur_insert_if_possible(
page_cursor = btr_cur_get_page_cur(cursor);
/* Now, try the insert */
- rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
- offsets, heap, n_ext, mtr);
+ rec = page_cur_tuple_insert(page_cursor, tuple, offsets, heap, n_ext,
+ mtr);
/* If the record did not fit, reorganize.
For compressed pages, page_cur_tuple_insert()
attempted this already. */
if (!rec && !page_cur_get_page_zip(page_cursor)
- && btr_page_reorganize(page_cursor, cursor->index, mtr)
- == DB_SUCCESS) {
- rec = page_cur_tuple_insert(
- page_cursor, tuple, cursor->index,
- offsets, heap, n_ext, mtr);
+ && btr_page_reorganize(page_cursor, mtr) == DB_SUCCESS) {
+ rec = page_cur_tuple_insert(page_cursor, tuple, offsets, heap,
+ n_ext, mtr);
}
- ut_ad(!rec || rec_offs_validate(rec, cursor->index, *offsets));
+ ut_ad(!rec || rec_offs_validate(rec, page_cursor->index, *offsets));
return(rec);
}
@@ -3141,7 +2988,7 @@ btr_cur_ins_lock_and_undo(
request if yes */
rec_t* rec = btr_cur_get_rec(cursor);
- dict_index_t* index = cursor->index;
+ dict_index_t* index = cursor->index();
ut_ad(!dict_index_is_online_ddl(index)
|| dict_index_is_clust(index)
@@ -3313,7 +3160,7 @@ btr_cur_optimistic_insert(
block = btr_cur_get_block(cursor);
page = buf_block_get_frame(block);
- index = cursor->index;
+ index = cursor->index();
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
ut_ad(!dict_index_is_online_ddl(index)
@@ -3429,8 +3276,7 @@ fail_err:
<< ib::hex(thr ? thr->graph->trx->id : 0)
<< ' ' << rec_printer(entry).str());
DBUG_EXECUTE_IF("do_page_reorganize",
- if (n_recs)
- ut_a(btr_page_reorganize(page_cursor, index, mtr)
+ ut_a(!n_recs || btr_page_reorganize(page_cursor, mtr)
== DB_SUCCESS););
/* Now, try the insert */
@@ -3473,9 +3319,8 @@ fail_err:
}
#endif
- *rec = page_cur_tuple_insert(
- page_cursor, entry, index, offsets, heap,
- n_ext, mtr);
+ *rec = page_cur_tuple_insert(page_cursor, entry, offsets, heap,
+ n_ext, mtr);
reorg = page_cursor_rec != page_cur_get_rec(page_cursor);
}
@@ -3497,10 +3342,10 @@ fail_err:
reorg = true;
/* If the record did not fit, reorganize */
- err = btr_page_reorganize(page_cursor, index, mtr);
+ err = btr_page_reorganize(page_cursor, mtr);
if (err != DB_SUCCESS
|| page_get_max_insert_size(page, 1) != max_size
- || !(*rec = page_cur_tuple_insert(page_cursor, entry, index,
+ || !(*rec = page_cur_tuple_insert(page_cursor, entry,
offsets, heap, n_ext,
mtr))) {
err = DB_CORRUPTION;
@@ -3596,7 +3441,7 @@ btr_cur_pessimistic_insert(
| BTR_NO_UNDO_LOG_FLAG)) */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
- dict_index_t* index = cursor->index;
+ dict_index_t* index = cursor->index();
big_rec_t* big_rec_vec = NULL;
bool inherit = false;
uint32_t n_reserved = 0;
@@ -3759,7 +3604,7 @@ btr_cur_upd_lock_and_undo(
ut_ad((thr != NULL) || (flags & BTR_NO_LOCKING_FLAG));
rec = btr_cur_get_rec(cursor);
- index = cursor->index;
+ index = cursor->index();
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(mtr->is_named_space(index->table->space));
@@ -3927,7 +3772,6 @@ btr_cur_update_alloc_zip_func(
/*==========================*/
page_zip_des_t* page_zip,/*!< in/out: compressed page */
page_cur_t* cursor, /*!< in/out: B-tree page cursor */
- dict_index_t* index, /*!< in: the index corresponding to cursor */
#ifdef UNIV_DEBUG
rec_offs* offsets,/*!< in/out: offsets of the cursor record */
#endif /* UNIV_DEBUG */
@@ -3936,6 +3780,7 @@ btr_cur_update_alloc_zip_func(
false=update-in-place */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
+ dict_index_t* index = cursor->index;
/* Have a local copy of the variables as these can change
dynamically. */
@@ -3962,7 +3807,7 @@ btr_cur_update_alloc_zip_func(
return(false);
}
- if (btr_page_reorganize(cursor, index, mtr) == DB_SUCCESS) {
+ if (btr_page_reorganize(cursor, mtr) == DB_SUCCESS) {
rec_offs_make_valid(page_cur_get_rec(cursor), index,
page_is_leaf(page), offsets);
@@ -4161,7 +4006,7 @@ btr_cur_update_in_place(
ut_ad(page_is_leaf(cursor->page_cur.block->page.frame));
rec = btr_cur_get_rec(cursor);
- index = cursor->index;
+ index = cursor->index();
ut_ad(!index->is_ibuf());
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
@@ -4193,7 +4038,7 @@ btr_cur_update_in_place(
if (!btr_cur_update_alloc_zip(
page_zip, btr_cur_get_page_cur(cursor),
- index, offsets, rec_offs_size(offsets),
+ offsets, rec_offs_size(offsets),
false, mtr)) {
return(DB_ZIP_OVERFLOW);
}
@@ -4470,7 +4315,7 @@ btr_cur_optimistic_update(
block = btr_cur_get_block(cursor);
page = buf_block_get_frame(block);
rec = btr_cur_get_rec(cursor);
- index = cursor->index;
+ index = cursor->index();
ut_ad(index->has_locking());
ut_ad(trx_id > 0 || (flags & BTR_KEEP_SYS_FLAG)
|| index->table->is_temporary());
@@ -4574,7 +4419,7 @@ any_extern:
}
if (!btr_cur_update_alloc_zip(
- page_zip, page_cursor, index, *offsets,
+ page_zip, page_cursor, *offsets,
new_rec_size, true, mtr)) {
return(DB_ZIP_OVERFLOW);
}
@@ -4669,7 +4514,7 @@ any_extern:
btr_search_update_hash_on_delete(cursor);
}
- page_cur_delete_rec(page_cursor, index, *offsets, mtr);
+ page_cur_delete_rec(page_cursor, *offsets, mtr);
if (!page_cur_move_to_prev(page_cursor)) {
return DB_CORRUPTION;
@@ -4690,7 +4535,7 @@ any_extern:
was a rollback, the shortened metadata record
would have too many fields, and we would be unable to
know the size of the freed record. */
- err = btr_page_reorganize(page_cursor, index, mtr);
+ err = btr_page_reorganize(page_cursor, mtr);
if (err != DB_SUCCESS) {
goto func_exit;
}
@@ -4829,7 +4674,7 @@ btr_cur_pessimistic_update(
block = btr_cur_get_block(cursor);
page_zip = buf_block_get_page_zip(block);
- index = cursor->index;
+ index = cursor->index();
ut_ad(index->has_locking());
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK |
@@ -5035,7 +4880,7 @@ btr_cur_pessimistic_update(
#endif /* UNIV_ZIP_DEBUG */
page_cursor = btr_cur_get_page_cur(cursor);
- page_cur_delete_rec(page_cursor, index, *offsets, mtr);
+ page_cur_delete_rec(page_cursor, *offsets, mtr);
if (!page_cur_move_to_prev(page_cursor)) {
err = DB_CORRUPTION;
@@ -5053,7 +4898,7 @@ btr_cur_pessimistic_update(
was a rollback, the shortened metadata record
would have too many fields, and we would be unable to
know the size of the freed record. */
- err = btr_page_reorganize(page_cursor, index, mtr);
+ err = btr_page_reorganize(page_cursor, mtr);
if (err != DB_SUCCESS) {
goto return_after_reservations;
}
@@ -5108,10 +4953,9 @@ btr_cur_pessimistic_update(
&& !big_rec_vec
&& page_is_leaf(block->page.frame)
&& !dict_index_is_online_ddl(index)) {
-
- mtr_memo_release(mtr, &index->lock,
- MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK);
-
+#if 0 // FIXME: this used to be a no-op, and will cause trouble if enabled
+ mtr->release(index->lock);
+#endif
/* NOTE: We cannot release root block latch here, because it
has segment header and already modified in most of cases.*/
}
@@ -5143,7 +4987,7 @@ btr_cur_pessimistic_update(
/* btr_page_split_and_insert() in
btr_cur_pessimistic_insert() invokes
- mtr_memo_release(mtr, index->lock, MTR_MEMO_SX_LOCK).
+ mtr->release(index->lock).
We must keep the index->lock when we created a
big_rec, so that row_upd_clust_rec() can store the
big_rec in the same mini-transaction. */
@@ -5171,7 +5015,7 @@ btr_cur_pessimistic_update(
ut_a(err == DB_SUCCESS);
ut_a(rec);
ut_a(dummy_big_rec == NULL);
- ut_ad(rec_offs_validate(rec, cursor->index, *offsets));
+ ut_ad(rec_offs_validate(rec, cursor->index(), *offsets));
page_cursor->rec = rec;
/* Multiple transactions cannot simultaneously operate on the
@@ -5208,7 +5052,7 @@ btr_cur_pessimistic_update(
was a rollback, the shortened metadata record
would have too many fields, and we would be unable to
know the size of the freed record. */
- err = btr_page_reorganize(page_cursor, index, mtr);
+ err = btr_page_reorganize(page_cursor, mtr);
if (err != DB_SUCCESS) {
goto return_after_reservations;
}
@@ -5361,12 +5205,12 @@ btr_cur_compress_if_useful(
adjusted even when compression occurs */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
- ut_ad(mtr->memo_contains_flagged(&cursor->index->lock,
+ ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock,
MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK));
ut_ad(mtr->memo_contains_flagged(btr_cur_get_block(cursor),
MTR_MEMO_PAGE_X_FIX));
- if (cursor->index->is_spatial()) {
+ if (cursor->index()->is_spatial()) {
const trx_t* trx = cursor->rtr_info->thr
? thr_get_trx(cursor->rtr_info->thr)
: NULL;
@@ -5411,23 +5255,23 @@ btr_cur_optimistic_delete(
ut_ad(flags == 0 || flags == BTR_CREATE_FLAG);
ut_ad(mtr->memo_contains_flagged(btr_cur_get_block(cursor),
MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr->is_named_space(cursor->index->table->space));
- ut_ad(!cursor->index->is_dummy);
+ ut_ad(mtr->is_named_space(cursor->index()->table->space));
+ ut_ad(!cursor->index()->is_dummy);
/* This is intended only for leaf page deletions */
block = btr_cur_get_block(cursor);
- ut_ad(block->page.id().space() == cursor->index->table->space->id);
+ ut_ad(block->page.id().space() == cursor->index()->table->space->id);
ut_ad(page_is_leaf(buf_block_get_frame(block)));
- ut_ad(!dict_index_is_online_ddl(cursor->index)
- || dict_index_is_clust(cursor->index)
+ ut_ad(!dict_index_is_online_ddl(cursor->index())
+ || cursor->index()->is_clust()
|| (flags & BTR_CREATE_FLAG));
rec = btr_cur_get_rec(cursor);
- offsets = rec_get_offsets(rec, cursor->index, offsets,
- cursor->index->n_core_fields,
+ offsets = rec_get_offsets(rec, cursor->index(), offsets,
+ cursor->index()->n_core_fields,
ULINT_UNDEFINED, &heap);
dberr_t err = DB_SUCCESS;
@@ -5437,23 +5281,24 @@ btr_cur_optimistic_delete(
mtr)) {
/* prefetch siblings of the leaf for the pessimistic
operation. */
- btr_cur_prefetch_siblings(block, cursor->index);
+ btr_cur_prefetch_siblings(block, cursor->index());
err = DB_FAIL;
goto func_exit;
}
- if (UNIV_UNLIKELY(block->page.id().page_no() == cursor->index->page
+ if (UNIV_UNLIKELY(block->page.id().page_no() == cursor->index()->page
&& page_get_n_recs(block->page.frame) == 1
- + (cursor->index->is_instant()
- && !rec_is_metadata(rec, *cursor->index))
- && !cursor->index->must_avoid_clear_instant_add())) {
+ + (cursor->index()->is_instant()
+ && !rec_is_metadata(rec, *cursor->index()))
+ && !cursor->index()
+ ->must_avoid_clear_instant_add())) {
/* The whole index (and table) becomes logically empty.
Empty the whole page. That is, if we are deleting the
only user record, also delete the metadata record
if one exists for instant ADD COLUMN (not generic ALTER TABLE).
If we are deleting the metadata record and the
table becomes empty, clean up the whole page. */
- dict_index_t* index = cursor->index;
+ dict_index_t* index = cursor->index();
const rec_t* first_rec = page_rec_get_next_const(
page_get_infimum_rec(block->page.frame));
if (UNIV_UNLIKELY(!first_rec)) {
@@ -5498,17 +5343,17 @@ btr_cur_optimistic_delete(
If this is a recovered transaction, then
index->is_instant() will hold until the
insert into SYS_COLUMNS is rolled back. */
- ut_ad(cursor->index->table->supports_instant());
- ut_ad(cursor->index->is_primary());
+ ut_ad(cursor->index()->table->supports_instant());
+ ut_ad(cursor->index()->is_primary());
ut_ad(!page_zip);
page_cur_delete_rec(btr_cur_get_page_cur(cursor),
- cursor->index, offsets, mtr);
+ offsets, mtr);
/* We must empty the PAGE_FREE list, because
after rollback, this deleted metadata record
would have too many fields, and we would be
unable to know the size of the freed record. */
err = btr_page_reorganize(btr_cur_get_page_cur(cursor),
- cursor->index, mtr);
+ mtr);
goto func_exit;
} else {
if (!flags) {
@@ -5520,12 +5365,14 @@ btr_cur_optimistic_delete(
if (page_zip) {
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page, cursor->index));
+ ut_a(page_zip_validate(page_zip, page,
+ cursor->index()));
#endif /* UNIV_ZIP_DEBUG */
page_cur_delete_rec(btr_cur_get_page_cur(cursor),
- cursor->index, offsets, mtr);
+ offsets, mtr);
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page, cursor->index));
+ ut_a(page_zip_validate(page_zip, page,
+ cursor->index()));
#endif /* UNIV_ZIP_DEBUG */
/* On compressed pages, the IBUF_BITMAP_FREE
@@ -5539,14 +5386,14 @@ btr_cur_optimistic_delete(
page, 1);
page_cur_delete_rec(btr_cur_get_page_cur(cursor),
- cursor->index, offsets, mtr);
+ offsets, mtr);
/* The change buffer does not handle inserts
into non-leaf pages, into clustered indexes,
or into the change buffer. */
- if (!dict_index_is_clust(cursor->index)
- && !cursor->index->table->is_temporary()
- && !dict_index_is_ibuf(cursor->index)) {
+ if (!cursor->index()->is_clust()
+ && !cursor->index()->table->is_temporary()
+ && !dict_index_is_ibuf(cursor->index())) {
ibuf_update_free_bits_low(block, max_ins, mtr);
}
}
@@ -5716,13 +5563,13 @@ btr_cur_pessimistic_delete(
btr_search_update_hash_on_delete(cursor);
} else {
page_cur_delete_rec(btr_cur_get_page_cur(cursor),
- index, offsets, mtr);
+ offsets, mtr);
/* We must empty the PAGE_FREE list, because
after rollback, this deleted metadata record
would carry too many fields, and we would be
unable to know the size of the freed record. */
*err = btr_page_reorganize(btr_cur_get_page_cur(cursor),
- index, mtr);
+ mtr);
ut_ad(!ret);
goto err_exit;
}
@@ -5745,6 +5592,10 @@ discard_page:
goto err_exit;
}
+ btr_cur_t cursor;
+ cursor.page_cur.index = index;
+ cursor.page_cur.block = block;
+
if (!page_has_prev(page)) {
/* If we delete the leftmost node pointer on a
non-leaf level, we must mark the new leftmost node
@@ -5756,22 +5607,19 @@ discard_page:
we need to update parent page. */
rtr_mbr_t father_mbr;
rec_t* father_rec;
- btr_cur_t father_cursor;
rec_offs* offsets;
ulint len;
- rtr_page_get_father_block(NULL, heap, index,
- block, mtr, NULL,
- &father_cursor);
- offsets = rec_get_offsets(
- btr_cur_get_rec(&father_cursor), index, NULL,
- 0, ULINT_UNDEFINED, &heap);
+ rtr_page_get_father_block(NULL, heap, mtr, NULL,
+ &cursor);
+ father_rec = btr_cur_get_rec(&cursor);
+ offsets = rec_get_offsets(father_rec, index, NULL,
+ 0, ULINT_UNDEFINED, &heap);
- father_rec = btr_cur_get_rec(&father_cursor);
rtr_read_mbr(rec_get_nth_field(
father_rec, offsets, 0, &len), &father_mbr);
- rtr_update_mbr_field(&father_cursor, offsets, NULL,
+ rtr_update_mbr_field(&cursor, offsets, NULL,
page, &father_mbr, next_rec, mtr);
ut_d(parent_latched = true);
} else {
@@ -5779,8 +5627,7 @@ discard_page:
on a page, we have to change the parent node pointer
so that it is equal to the new leftmost node pointer
on the page */
- btr_cur_t cursor;
- ret = btr_page_get_father(index, block, mtr, &cursor);
+ ret = btr_page_get_father(mtr, &cursor);
if (!ret) {
*err = DB_CORRUPTION;
goto err_exit;
@@ -5820,7 +5667,7 @@ got_err:
index, page, BTR_INTENTION_DELETE, rec,
btr_node_ptr_max_size(index),
block->zip_size(), mtr);
- page_cur_delete_rec(btr_cur_get_page_cur(cursor), index,
+ page_cur_delete_rec(btr_cur_get_page_cur(cursor),
offsets, mtr);
if (min_mark_next_rec) {
@@ -5856,10 +5703,9 @@ err_exit:
if (!srv_read_only_mode
&& page_is_leaf(page)
&& !dict_index_is_online_ddl(index)) {
-
- mtr_memo_release(mtr, &index->lock,
- MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK);
-
+#if 0 // FIXME: this used to be a no-op, and will cause trouble if enabled
+ mtr->release(index->lock);
+#endif
/* NOTE: We cannot release root block latch here, because it
has segment header and already modified in most of cases.*/
}
@@ -6010,7 +5856,8 @@ public:
if (dtuple_get_n_fields(&m_tuple) > 0)
{
m_up_bytes= m_low_bytes= 0;
- if (page_cur_search_with_match(m_block, index(), &m_tuple, m_page_mode,
+ m_page_cur.block= m_block;
+ if (page_cur_search_with_match(&m_tuple, m_page_mode,
&m_up_match, &m_low_match, &m_page_cur,
nullptr))
return false;
@@ -6101,8 +5948,8 @@ public:
}
ut_ad(page_rec_is_supremum(page_cur_get_rec(&m_page_cur)));
- /* The range specified is wihout a right border, just 'x > 123' or 'x >=
- 123' and btr_cur_open_at_index_side() positioned the cursor on the
+ /* The range specified is without a right border, just 'x > 123'
+ or 'x >= 123' and search_on_page() positioned the cursor on the
supremum record on the rightmost page, which must not be counted. */
return false;
}
@@ -6822,8 +6669,9 @@ struct btr_blob_log_check_t {
+ offs;
} else {
ut_ad(m_pcur->rel_pos == BTR_PCUR_ON);
+ mtr_sx_lock_index(index, m_mtr);
ut_a(m_pcur->restore_position(
- BTR_MODIFY_LEAF | BTR_MODIFY_EXTERNAL,
+ BTR_MODIFY_LEAF_ALREADY_LATCHED,
m_mtr) == btr_pcur_t::SAME_ALL);
}
diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc
index 37219210883..3009f04021f 100644
--- a/storage/innobase/btr/btr0defragment.cc
+++ b/storage/innobase/btr/btr0defragment.cc
@@ -169,7 +169,7 @@ btr_defragment_find_index(
@return whether the operation was interrupted */
bool btr_defragment_add_index(btr_pcur_t *pcur, THD *thd)
{
- dict_stats_empty_defrag_summary(pcur->btr_cur.index);
+ dict_stats_empty_defrag_summary(pcur->index());
pthread_cond_t cond;
pthread_cond_init(&cond, nullptr);
btr_defragment_item_t item(pcur, &cond);
@@ -209,7 +209,7 @@ btr_defragment_remove_table(
mysql_mutex_lock(&btr_defragment_mutex);
for (auto item : btr_defragment_wq)
{
- if (item->cond && table == item->pcur->btr_cur.index->table)
+ if (item->cond && table == item->pcur->index()->table)
{
pthread_cond_signal(item->cond);
item->cond= nullptr;
@@ -405,7 +405,10 @@ btr_defragment_merge_pages(
}
}
btr_cur_t parent;
- if (!btr_page_get_father(index, from_block, mtr, &parent)) {
+ parent.page_cur.index = index;
+ parent.page_cur.block = from_block;
+
+ if (!btr_page_get_father(mtr, &parent)) {
to_block = nullptr;
} else if (n_recs_to_move == n_recs) {
/* The whole page is merged with the previous page,
@@ -690,7 +693,7 @@ processed:
}
log_free_check();
mtr_start(&mtr);
- dict_index_t *index = item->pcur->btr_cur.index;
+ dict_index_t *index = item->pcur->index();
index->set_modified(mtr);
/* To follow the latching order defined in WL#6326,
acquire index->lock X-latch. This entitles us to
diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc
index e49ef672928..46b8d487850 100644
--- a/storage/innobase/btr/btr0pcur.cc
+++ b/storage/innobase/btr/btr0pcur.cc
@@ -30,25 +30,6 @@ Created 2/23/1996 Heikki Tuuri
#include "trx0trx.h"
/**************************************************************//**
-Allocates memory for a persistent cursor object and initializes the cursor.
-@return own: persistent cursor */
-btr_pcur_t*
-btr_pcur_create_for_mysql(void)
-/*============================*/
-{
- btr_pcur_t* pcur;
- DBUG_ENTER("btr_pcur_create_for_mysql");
-
- pcur = (btr_pcur_t*) ut_malloc_nokey(sizeof(btr_pcur_t));
-
- pcur->btr_cur.index = NULL;
- btr_pcur_init(pcur);
-
- DBUG_PRINT("btr_pcur_create_for_mysql", ("pcur: %p", pcur));
- DBUG_RETURN(pcur);
-}
-
-/**************************************************************//**
Resets a persistent cursor object, freeing ::old_rec_buf if it is
allocated and resetting the other members to their initial values. */
void
@@ -56,35 +37,18 @@ btr_pcur_reset(
/*===========*/
btr_pcur_t* cursor) /*!< in, out: persistent cursor */
{
- btr_pcur_free(cursor);
+ ut_free(cursor->old_rec_buf);
+ memset(&cursor->btr_cur.page_cur, 0, sizeof(page_cur_t));
cursor->old_rec_buf = NULL;
- cursor->btr_cur.index = NULL;
- cursor->btr_cur.page_cur.rec = NULL;
cursor->old_rec = NULL;
cursor->old_n_core_fields = 0;
cursor->old_n_fields = 0;
- cursor->old_stored = false;
cursor->latch_mode = BTR_NO_LATCHES;
cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
}
/**************************************************************//**
-Frees the memory for a persistent cursor object. */
-void
-btr_pcur_free_for_mysql(
-/*====================*/
- btr_pcur_t* cursor) /*!< in, own: persistent cursor */
-{
- DBUG_ENTER("btr_pcur_free_for_mysql");
- DBUG_PRINT("btr_pcur_free_for_mysql", ("pcur: %p", cursor));
-
- btr_pcur_free(cursor);
- ut_free(cursor);
- DBUG_VOID_RETURN;
-}
-
-/**************************************************************//**
The position of the cursor is stored by taking an initial segment of the
record the cursor is positioned on, before, or after, and copying it to the
cursor data structure, or just setting a flag if the cursor id before the
@@ -125,8 +89,6 @@ btr_pcur_store_position(
&& mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
| MTR_MEMO_SX_LOCK)));
- cursor->old_stored = true;
-
if (page_is_empty(block->page.frame)) {
/* It must be an empty index tree; NOTE that in this case
we do not store the modify_clock, but always do a search
@@ -256,11 +218,12 @@ otherwise. */
struct optimistic_latch_leaves
{
btr_pcur_t *const cursor;
- ulint *latch_mode;
+ btr_latch_mode *latch_mode;
mtr_t *const mtr;
- optimistic_latch_leaves(btr_pcur_t *cursor, ulint *latch_mode, mtr_t *mtr)
- :cursor(cursor), latch_mode(latch_mode), mtr(mtr) {}
+ optimistic_latch_leaves(btr_pcur_t *cursor, btr_latch_mode *latch_mode,
+ mtr_t *mtr)
+ : cursor(cursor), latch_mode(latch_mode), mtr(mtr) {}
bool operator() (buf_block_t *hint) const
{
@@ -292,7 +255,7 @@ record with the same unique field values as in the stored record,
btr_pcur_t::NOT_SAME cursor position is not on user rec or points on
the record with not the samebuniq field values as in the stored */
btr_pcur_t::restore_status
-btr_pcur_t::restore_position(ulint restore_latch_mode, mtr_t *mtr)
+btr_pcur_t::restore_position(btr_latch_mode restore_latch_mode, mtr_t *mtr)
{
dict_index_t* index;
dtuple_t* tuple;
@@ -301,7 +264,6 @@ btr_pcur_t::restore_position(ulint restore_latch_mode, mtr_t *mtr)
mem_heap_t* heap;
ut_ad(mtr->is_active());
- //ut_ad(cursor->old_stored);
ut_ad(pos_state == BTR_PCUR_WAS_POSITIONED
|| pos_state == BTR_PCUR_IS_POSITIONED);
@@ -313,10 +275,9 @@ btr_pcur_t::restore_position(ulint restore_latch_mode, mtr_t *mtr)
/* In these cases we do not try an optimistic restoration,
but always do a search */
- if (btr_cur_open_at_index_side(
- rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
- index, restore_latch_mode,
- &btr_cur, 0, mtr) != DB_SUCCESS) {
+ if (btr_cur.open_leaf(rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
+ index, restore_latch_mode, mtr)
+ != DB_SUCCESS) {
return restore_status::CORRUPTED;
}
@@ -333,9 +294,10 @@ btr_pcur_t::restore_position(ulint restore_latch_mode, mtr_t *mtr)
ut_a(old_n_core_fields <= index->n_core_fields);
ut_a(old_n_fields);
- switch (restore_latch_mode) {
- case BTR_SEARCH_LEAF:
- case BTR_MODIFY_LEAF:
+ static_assert(BTR_SEARCH_PREV == (4 | BTR_SEARCH_LEAF), "");
+ static_assert(BTR_MODIFY_PREV == (4 | BTR_MODIFY_LEAF), "");
+
+ switch (restore_latch_mode | 4) {
case BTR_SEARCH_PREV:
case BTR_MODIFY_PREV:
/* Try optimistic restoration. */
@@ -420,7 +382,7 @@ btr_pcur_t::restore_position(ulint restore_latch_mode, mtr_t *mtr)
mode = PAGE_CUR_UNSUPP;
}
- if (btr_pcur_open_with_no_init(index, tuple, mode, restore_latch_mode,
+ if (btr_pcur_open_with_no_init(tuple, mode, restore_latch_mode,
this, mtr) != DB_SUCCESS) {
mem_heap_free(heap);
return restore_status::CORRUPTED;
@@ -450,7 +412,6 @@ btr_pcur_t::restore_position(ulint restore_latch_mode, mtr_t *mtr)
block_when_stored.store(btr_pcur_get_block(this));
modify_clock= buf_block_get_modify_clock(
block_when_stored.block());
- old_stored= true;
mem_heap_free(heap);
@@ -487,7 +448,7 @@ btr_pcur_move_to_next_page(
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
ut_ad(btr_pcur_is_after_last_on_page(cursor));
- cursor->old_stored = false;
+ cursor->old_rec = nullptr;
const page_t* page = btr_pcur_get_page(cursor);
const uint32_t next_page_no = btr_page_get_next(page);
@@ -515,7 +476,7 @@ btr_pcur_move_to_next_page(
dberr_t err;
buf_block_t* next_block = btr_block_get(
- *btr_pcur_get_btr_cur(cursor)->index, next_page_no, mode,
+ *cursor->index(), next_page_no, mode,
page_is_leaf(page), mtr, &err);
if (UNIV_UNLIKELY(!next_block)) {
@@ -529,12 +490,13 @@ btr_pcur_move_to_next_page(
return DB_CORRUPTION;
}
- btr_leaf_page_release(btr_pcur_get_block(cursor), mode, mtr);
-
page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
ut_d(page_check_dir(next_page));
- return err;
+
+ const auto s = mtr->get_savepoint();
+ mtr->rollback_to_savepoint(s - 2, s - 1);
+ return DB_SUCCESS;
}
MY_ATTRIBUTE((nonnull,warn_unused_result))
@@ -558,7 +520,7 @@ btr_pcur_move_backward_from_page(
ut_ad(btr_pcur_is_before_first_on_page(cursor));
ut_ad(!btr_pcur_is_before_first_in_tree(cursor));
- const ulint latch_mode = cursor->latch_mode;
+ const auto latch_mode = cursor->latch_mode;
ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF);
btr_pcur_store_position(cursor, mtr);
@@ -570,31 +532,32 @@ btr_pcur_move_backward_from_page(
static_assert(BTR_SEARCH_PREV == (4 | BTR_SEARCH_LEAF), "");
static_assert(BTR_MODIFY_PREV == (4 | BTR_MODIFY_LEAF), "");
- if (UNIV_UNLIKELY(cursor->restore_position(4 | latch_mode, mtr)
+ if (UNIV_UNLIKELY(cursor->restore_position(
+ btr_latch_mode(4 | latch_mode), mtr)
== btr_pcur_t::CORRUPTED)) {
return true;
}
- buf_block_t* prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
+ buf_block_t* release_block = nullptr;
if (!page_has_prev(btr_pcur_get_page(cursor))) {
} else if (btr_pcur_is_before_first_on_page(cursor)) {
- btr_leaf_page_release(btr_pcur_get_block(cursor),
- latch_mode, mtr);
-
- page_cur_set_after_last(prev_block,
+ release_block = btr_pcur_get_block(cursor);
+ page_cur_set_after_last(cursor->btr_cur.left_block,
btr_pcur_get_page_cur(cursor));
} else {
/* The repositioned cursor did not end on an infimum
record on a page. Cursor repositioning acquired a latch
also on the previous page, but we do not need the latch:
release it. */
- prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
- btr_leaf_page_release(prev_block, latch_mode, mtr);
+ release_block = cursor->btr_cur.left_block;
}
cursor->latch_mode = latch_mode;
- cursor->old_stored = false;
+ cursor->old_rec = nullptr;
+ if (release_block) {
+ mtr->release(*release_block);
+ }
return false;
}
@@ -612,7 +575,7 @@ btr_pcur_move_to_prev(
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- cursor->old_stored = false;
+ cursor->old_rec = nullptr;
if (btr_pcur_is_before_first_on_page(cursor)) {
return (!btr_pcur_is_before_first_in_tree(cursor)
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 09f2dac3ccf..49a5d0ae85a 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -302,7 +302,7 @@ are consistent.
@param[in] cursor cursor which was just positioned */
static void btr_search_info_update_hash(btr_search_t *info, btr_cur_t *cursor)
{
- dict_index_t* index = cursor->index;
+ dict_index_t* index = cursor->index();
int cmp;
if (dict_index_is_ibuf(index)) {
@@ -704,14 +704,14 @@ btr_search_update_hash_ref(
return;
}
- if (index != cursor->index) {
- ut_ad(index->id == cursor->index->id);
+ if (index != cursor->index()) {
+ ut_ad(index->id == cursor->index()->id);
btr_search_drop_page_hash_index(block);
return;
}
ut_ad(block->page.id().space() == index->table->space_id);
- ut_ad(index == cursor->index);
+ ut_ad(index == cursor->index());
ut_ad(!dict_index_is_ibuf(index));
auto part = btr_search_sys.get_part(*index);
part->latch.wr_lock(SRW_LOCK_CALL);
@@ -784,7 +784,7 @@ btr_search_check_guess(
bool success = false;
rec_offs_init(offsets_);
- n_unique = dict_index_get_n_unique_in_tree(cursor->index);
+ n_unique = dict_index_get_n_unique_in_tree(cursor->index());
rec = btr_cur_get_rec(cursor);
@@ -792,7 +792,7 @@ btr_search_check_guess(
|| !page_rec_is_leaf(rec))) {
ut_ad("corrupted index" == 0);
return false;
- } else if (cursor->index->table->not_redundant()) {
+ } else if (cursor->index()->table->not_redundant()) {
switch (rec_get_status(rec)) {
case REC_STATUS_INSTANT:
case REC_STATUS_ORDINARY:
@@ -805,10 +805,10 @@ btr_search_check_guess(
match = 0;
- offsets = rec_get_offsets(rec, cursor->index, offsets,
- cursor->index->n_core_fields,
+ offsets = rec_get_offsets(rec, cursor->index(), offsets,
+ cursor->index()->n_core_fields,
n_unique, &heap);
- cmp = cmp_dtuple_rec_with_match(tuple, rec, cursor->index, offsets,
+ cmp = cmp_dtuple_rec_with_match(tuple, rec, cursor->index(), offsets,
&match);
if (mode == PAGE_CUR_GE) {
@@ -860,7 +860,7 @@ btr_search_check_guess(
goto exit_func;
}
- if (cursor->index->table->not_redundant()) {
+ if (cursor->index()->table->not_redundant()) {
switch (rec_get_status(prev_rec)) {
case REC_STATUS_INSTANT:
case REC_STATUS_ORDINARY:
@@ -871,11 +871,12 @@ btr_search_check_guess(
}
}
- offsets = rec_get_offsets(prev_rec, cursor->index, offsets,
- cursor->index->n_core_fields,
+ offsets = rec_get_offsets(prev_rec, cursor->index(), offsets,
+ cursor->index()->n_core_fields,
n_unique, &heap);
- cmp = cmp_dtuple_rec_with_match(
- tuple, prev_rec, cursor->index, offsets, &match);
+ cmp = cmp_dtuple_rec_with_match(tuple, prev_rec,
+ cursor->index(), offsets,
+ &match);
if (mode == PAGE_CUR_GE) {
success = cmp > 0;
} else {
@@ -900,7 +901,7 @@ btr_search_check_guess(
goto exit_func;
}
- if (cursor->index->table->not_redundant()) {
+ if (cursor->index()->table->not_redundant()) {
switch (rec_get_status(next_rec)) {
case REC_STATUS_INSTANT:
case REC_STATUS_ORDINARY:
@@ -911,11 +912,11 @@ btr_search_check_guess(
}
}
- offsets = rec_get_offsets(next_rec, cursor->index, offsets,
- cursor->index->n_core_fields,
+ offsets = rec_get_offsets(next_rec, cursor->index(), offsets,
+ cursor->index()->n_core_fields,
n_unique, &heap);
cmp = cmp_dtuple_rec_with_match(
- tuple, next_rec, cursor->index, offsets, &match);
+ tuple, next_rec, cursor->index(), offsets, &match);
if (mode == PAGE_CUR_LE) {
success = cmp < 0;
cursor->up_match = match;
@@ -1099,16 +1100,16 @@ btr_search_guess_on_hash(
part->latch.rd_lock(SRW_LOCK_CALL);
if (!btr_search_enabled) {
- goto fail;
+ goto ahi_release_and_fail;
}
rec = static_cast<const rec_t*>(
ha_search_and_get_data(&part->table, fold));
if (!rec) {
-fail:
+ahi_release_and_fail:
part->latch.rd_unlock();
-
+fail:
btr_search_failure(info, cursor);
return false;
}
@@ -1117,66 +1118,52 @@ fail:
buf_pool_t::hash_chain& chain = buf_pool.page_hash.cell_get(
block->page.id().fold());
- bool fail, got_latch;
+ bool got_latch;
{
transactional_shared_lock_guard<page_hash_latch> g{
buf_pool.page_hash.lock_get(chain)};
-
- const auto state = block->page.state();
- if (state == buf_page_t::REMOVE_HASH) {
- /* Another thread is just freeing the block
- from the LRU list of the buffer pool: do not
- try to access this page. */
- goto fail;
- }
- if (UNIV_UNLIKELY(state < buf_page_t::UNFIXED)) {
-#ifndef NO_ELISION
- xend();
-#endif
- ut_error;
- }
-
- fail = index != block->index && index_id == block->index->id;
got_latch = (latch_mode == BTR_SEARCH_LEAF)
? block->page.lock.s_lock_try()
: block->page.lock.x_lock_try();
}
- ut_a(!fail || block->index->freed());
if (!got_latch) {
- goto fail;
+ goto ahi_release_and_fail;
+ }
+
+ const auto state = block->page.state();
+ if (UNIV_UNLIKELY(state < buf_page_t::UNFIXED)) {
+ ut_ad(state == buf_page_t::REMOVE_HASH);
+block_and_ahi_release_and_fail:
+ if (latch_mode == BTR_SEARCH_LEAF) {
+ block->page.lock.s_unlock();
+ } else {
+ block->page.lock.x_unlock();
+ }
+ goto ahi_release_and_fail;
+ }
+
+ ut_ad(state < buf_page_t::READ_FIX || state >= buf_page_t::WRITE_FIX);
+ ut_ad(state < buf_page_t::READ_FIX || latch_mode == BTR_SEARCH_LEAF);
+
+ if (index != block->index && index_id == block->index->id) {
+ ut_a(block->index->freed());
+ goto block_and_ahi_release_and_fail;
}
block->page.fix();
block->page.set_accessed();
buf_page_make_young_if_needed(&block->page);
- ut_ad(!block->page.is_read_fixed());
- ut_ad(latch_mode == BTR_SEARCH_LEAF || !block->page.is_io_fixed());
static_assert(ulint{MTR_MEMO_PAGE_S_FIX} == ulint{BTR_SEARCH_LEAF},
"");
static_assert(ulint{MTR_MEMO_PAGE_X_FIX} == ulint{BTR_MODIFY_LEAF},
"");
- mtr->memo_push(block, mtr_memo_type_t(latch_mode));
-
- ++buf_pool.stat.n_page_gets;
part->latch.rd_unlock();
- if (UNIV_UNLIKELY(fail)) {
- goto fail_and_release_page;
- }
-
- DBUG_ASSERT(!block->page.is_freed());
-
- if (!block->page.in_file()) {
- ut_ad(block->page.state() == buf_page_t::REMOVE_HASH);
-
-fail_and_release_page:
- btr_leaf_page_release(block, latch_mode, mtr);
+ ++buf_pool.stat.n_page_gets;
- btr_search_failure(info, cursor);
- return false;
- }
+ mtr->memo_push(block, mtr_memo_type_t(latch_mode));
ut_ad(page_rec_is_user_rec(rec));
@@ -1191,7 +1178,8 @@ fail_and_release_page:
right. */
if (index_id != btr_page_get_index_id(block->page.frame)
|| !btr_search_check_guess(cursor, false, tuple, mode)) {
- goto fail_and_release_page;
+ mtr->release_last_page();
+ goto fail;
}
if (info->n_hash_potential < BTR_SEARCH_BUILD_LIMIT + 5) {
@@ -1199,41 +1187,6 @@ fail_and_release_page:
info->n_hash_potential++;
}
-#ifdef notdefined
- /* These lines of code can be used in a debug version to check
- the correctness of the searched cursor position: */
-
- info->last_hash_succ = FALSE;
-
- /* Currently, does not work if the following fails: */
- ut_ad(!ahi_latch);
-
- btr_leaf_page_release(block, latch_mode, mtr);
-
- btr_cur_search_to_nth_level(
- index, 0, tuple, mode, latch_mode, &cursor2, 0, mtr);
-
- if (mode == PAGE_CUR_GE
- && page_rec_is_supremum(btr_cur_get_rec(&cursor2))) {
-
- /* If mode is PAGE_CUR_GE, then the binary search
- in the index tree may actually take us to the supremum
- of the previous page */
-
- info->last_hash_succ = FALSE;
-
- btr_pcur_open_on_user_rec(
- index, tuple, mode, latch_mode, &pcur, mtr);
-
- ut_ad(btr_pcur_get_rec(&pcur) == btr_cur_get_rec(cursor));
- } else {
- ut_ad(btr_cur_get_rec(&cursor2) == btr_cur_get_rec(cursor));
- }
-
- /* NOTE that it is theoretically possible that the above assertions
- fail if the page of the cursor gets removed from the buffer pool
- meanwhile! Thus it might not be a bug. */
-#endif
info->last_hash_succ = TRUE;
#ifdef UNIV_SEARCH_PERF_STAT
@@ -1691,7 +1644,7 @@ exit_func:
@param[in,out] cursor cursor which was just positioned */
void btr_search_info_update_slow(btr_search_t *info, btr_cur_t *cursor)
{
- srw_spin_lock* ahi_latch = &btr_search_sys.get_part(*cursor->index)
+ srw_spin_lock* ahi_latch = &btr_search_sys.get_part(*cursor->index())
->latch;
buf_block_t* block = btr_cur_get_block(cursor);
@@ -1706,7 +1659,7 @@ void btr_search_info_update_slow(btr_search_t *info, btr_cur_t *cursor)
if (build_index || (cursor->flag == BTR_CUR_HASH_FAIL)) {
- btr_search_check_free_space_in_heap(cursor->index);
+ btr_search_check_free_space_in_heap(cursor->index());
}
if (cursor->flag == BTR_CUR_HASH_FAIL) {
@@ -1723,7 +1676,7 @@ void btr_search_info_update_slow(btr_search_t *info, btr_cur_t *cursor)
/* Note that since we did not protect block->n_fields etc.
with any semaphore, the values can be inconsistent. We have
to check inside the function call that they make sense. */
- btr_search_build_page_hash_index(cursor->index, block,
+ btr_search_build_page_hash_index(cursor->index(), block,
ahi_latch,
block->n_fields,
block->n_bytes,
@@ -1835,15 +1788,15 @@ void btr_search_update_hash_on_delete(btr_cur_t *cursor)
return;
}
- ut_ad(!cursor->index->table->is_temporary());
+ ut_ad(!cursor->index()->table->is_temporary());
- if (index != cursor->index) {
+ if (index != cursor->index()) {
btr_search_drop_page_hash_index(block);
return;
}
ut_ad(block->page.id().space() == index->table->space_id);
- ut_a(index == cursor->index);
+ ut_a(index == cursor->index());
ut_a(block->curr_n_fields > 0 || block->curr_n_bytes > 0);
ut_ad(!dict_index_is_ibuf(index));
@@ -1890,7 +1843,7 @@ void btr_search_update_hash_node_on_insert(btr_cur_t *cursor,
dict_index_t* index;
rec_t* rec;
- ut_ad(ahi_latch == &btr_search_sys.get_part(*cursor->index)->latch);
+ ut_ad(ahi_latch == &btr_search_sys.get_part(*cursor->index())->latch);
if (!btr_search_enabled) {
return;
@@ -1909,15 +1862,15 @@ void btr_search_update_hash_node_on_insert(btr_cur_t *cursor,
return;
}
- ut_ad(!cursor->index->table->is_temporary());
+ ut_ad(!cursor->index()->table->is_temporary());
- if (index != cursor->index) {
- ut_ad(index->id == cursor->index->id);
+ if (index != cursor->index()) {
+ ut_ad(index->id == cursor->index()->id);
btr_search_drop_page_hash_index(block);
return;
}
- ut_a(cursor->index == index);
+ ut_a(cursor->index() == index);
ut_ad(!dict_index_is_ibuf(index));
ahi_latch->wr_lock(SRW_LOCK_CALL);
@@ -1934,7 +1887,7 @@ void btr_search_update_hash_node_on_insert(btr_cur_t *cursor,
&& !block->curr_left_side) {
if (const rec_t *new_rec = page_rec_get_next_const(rec)) {
if (ha_search_and_update_if_found(
- &btr_search_sys.get_part(*cursor->index)
+ &btr_search_sys.get_part(*cursor->index())
->table,
cursor->fold, rec, block, new_rec)) {
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_UPDATED);
@@ -1977,7 +1930,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor,
rec_offs* offsets = offsets_;
rec_offs_init(offsets_);
- ut_ad(ahi_latch == &btr_search_sys.get_part(*cursor->index)->latch);
+ ut_ad(ahi_latch == &btr_search_sys.get_part(*cursor->index())->latch);
ut_ad(page_is_leaf(btr_cur_get_page(cursor)));
if (!btr_search_enabled) {
@@ -2001,16 +1954,16 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor,
rec = btr_cur_get_rec(cursor);
- ut_ad(!cursor->index->table->is_temporary());
+ ut_ad(!cursor->index()->table->is_temporary());
- if (index != cursor->index) {
- ut_ad(index->id == cursor->index->id);
+ if (index != cursor->index()) {
+ ut_ad(index->id == cursor->index()->id);
drop:
btr_search_drop_page_hash_index(block);
return;
}
- ut_a(index == cursor->index);
+ ut_a(index == cursor->index());
ut_ad(!dict_index_is_ibuf(index));
n_fields = block->curr_n_fields;
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 31e523fa3ff..56ae36b4857 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -1712,6 +1712,14 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept
DBUG_PRINT("ib_log", ("checkpoint ended at " LSN_PF ", flushed to " LSN_PF,
next_checkpoint_lsn, get_flushed_lsn()));
+ if (overwrite_warned)
+ {
+ sql_print_information("InnoDB: Crash recovery was broken "
+ "between LSN=" LSN_PF
+ " and checkpoint LSN=" LSN_PF ".",
+ overwrite_warned, next_checkpoint_lsn);
+ overwrite_warned= 0;
+ }
latch.wr_unlock();
}
@@ -1884,6 +1892,7 @@ ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn)
record from a previous fil_names_clear() call, which we must
write out before we can advance the checkpoint. */
log_write_up_to(sync_lsn, true);
+ DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", return;);
log_checkpoint();
}
}
@@ -1898,6 +1907,8 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious)
if (recv_recovery_is_on())
recv_sys.apply(true);
+ DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", return;);
+
Atomic_relaxed<lsn_t> &limit= furious
? buf_flush_sync_lsn : buf_flush_async_lsn;
@@ -2252,6 +2263,7 @@ unemployed:
buf_pool.page_cleaner_set_idle(true);
DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", continue;);
+ DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", continue;);
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
@@ -2335,6 +2347,7 @@ do_checkpoint:
here should not affect correctness, because log_free_check()
should still be invoking checkpoints when needed. */
DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", goto next;);
+ DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", goto next;);
if (!recv_recovery_is_on() && srv_operation == SRV_OPERATION_NORMAL)
log_checkpoint();
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index fab6ff4db8e..e2afe17f892 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -755,11 +755,12 @@ dict_create_index_tree_step(
search_tuple = dict_create_search_tuple(node->ind_row, node->heap);
node->page_no = FIL_NULL;
+ pcur.btr_cur.page_cur.index =
+ UT_LIST_GET_FIRST(dict_sys.sys_indexes->indexes);
dberr_t err =
- btr_pcur_open(UT_LIST_GET_FIRST(dict_sys.sys_indexes->indexes),
- search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
- &pcur, &mtr);
+ btr_pcur_open(search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
+ &pcur, 0, &mtr);
if (err != DB_SUCCESS) {
func_exit:
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 51bb5dc4eba..e90dff03e16 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -4147,8 +4147,9 @@ void dict_set_corrupted(dict_index_t *index, const char *ctx)
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 2);
+ cursor.page_cur.index = sys_index;
- if (btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_LE,
+ if (btr_cur_search_to_nth_level(0, tuple, PAGE_CUR_LE,
BTR_MODIFY_LEAF, &cursor, &mtr)
!= DB_SUCCESS) {
goto fail;
@@ -4222,8 +4223,9 @@ dict_index_set_merge_threshold(
dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 2);
+ cursor.page_cur.index = sys_index;
- if (btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE,
+ if (btr_cur_search_to_nth_level(0, tuple, PAGE_CUR_GE,
BTR_MODIFY_LEAF, &cursor, &mtr)
!= DB_SUCCESS) {
goto func_exit;
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index 0e937ebe63b..1ee10ec8232 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -215,8 +215,9 @@ dict_startscan_system(
mtr_t* mtr, /*!< in: the mini-transaction */
dict_table_t* table) /*!< in: system table */
{
- if (btr_pcur_open_at_index_side(true, table->indexes.start, BTR_SEARCH_LEAF,
- pcur, true, 0, mtr) != DB_SUCCESS)
+ btr_pcur_init(pcur);
+ if (pcur->open_leaf(true, table->indexes.start, BTR_SEARCH_LEAF, mtr) !=
+ DB_SUCCESS)
return nullptr;
const rec_t *rec;
do
@@ -1316,8 +1317,9 @@ static dberr_t dict_load_columns(dict_table_t *table, unsigned use_uncommitted,
mach_write_to_8(table_id, table->id);
dfield_set_data(&dfield, table_id, 8);
dict_index_copy_types(&tuple, sys_index, 1);
+ pcur.btr_cur.page_cur.index = sys_index;
- dberr_t err = btr_pcur_open_on_user_rec(sys_index, &tuple, PAGE_CUR_GE,
+ dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
if (err != DB_SUCCESS) {
goto func_exit;
@@ -1446,9 +1448,9 @@ dict_load_virtual_col(dict_table_t *table, bool uncommitted, ulint nth_v_col)
dfield_set_data(&dfield[1], vcol_pos, 4);
dict_index_copy_types(&tuple, sys_virtual_index, 2);
+ pcur.btr_cur.page_cur.index = sys_virtual_index;
- dberr_t err = btr_pcur_open_on_user_rec(sys_virtual_index, &tuple,
- PAGE_CUR_GE,
+ dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
if (err != DB_SUCCESS) {
goto func_exit;
@@ -1686,8 +1688,9 @@ static dberr_t dict_load_fields(dict_index_t *index, bool uncommitted,
mach_write_to_8(index_id, index->id);
dfield_set_data(&dfield, index_id, 8);
dict_index_copy_types(&tuple, sys_index, 1);
+ pcur.btr_cur.page_cur.index = sys_index;
- dberr_t error = btr_pcur_open_on_user_rec(sys_index, &tuple,
+ dberr_t error = btr_pcur_open_on_user_rec(&tuple,
PAGE_CUR_GE, BTR_SEARCH_LEAF,
&pcur, &mtr);
if (error != DB_SUCCESS) {
@@ -1944,8 +1947,9 @@ dberr_t dict_load_indexes(dict_table_t *table, bool uncommitted,
mach_write_to_8(table_id, table->id);
dfield_set_data(&dfield, table_id, 8);
dict_index_copy_types(&tuple, sys_index, 1);
+ pcur.btr_cur.page_cur.index = sys_index;
- dberr_t error = btr_pcur_open_on_user_rec(sys_index, &tuple,
+ dberr_t error = btr_pcur_open_on_user_rec(&tuple,
PAGE_CUR_GE, BTR_SEARCH_LEAF,
&pcur, &mtr);
if (error != DB_SUCCESS) {
@@ -2338,11 +2342,12 @@ static dict_table_t *dict_load_table_one(const span<const char> &name,
};
dfield_set_data(&dfield, name.data(), name.size());
dict_index_copy_types(&tuple, sys_index, 1);
+ pcur.btr_cur.page_cur.index = sys_index;
bool uncommitted = false;
reload:
mtr.start();
- dberr_t err = btr_pcur_open_on_user_rec(sys_index, &tuple, PAGE_CUR_GE,
+ dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
if (err != DB_SUCCESS || !btr_pcur_is_on_user_rec(&pcur)) {
@@ -2596,10 +2601,11 @@ dict_load_table_on_id(
mach_write_to_8(id_buf, table_id);
dfield_set_data(&dfield, id_buf, 8);
dict_index_copy_types(&tuple, sys_table_ids, 1);
+ pcur.btr_cur.page_cur.index = sys_table_ids;
dict_table_t* table = nullptr;
- if (btr_pcur_open_on_user_rec(sys_table_ids, &tuple, PAGE_CUR_GE,
+ if (btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr)
== DB_SUCCESS
&& btr_pcur_is_on_user_rec(&pcur)) {
@@ -2703,9 +2709,10 @@ static dberr_t dict_load_foreign_cols(dict_foreign_t *foreign, trx_id_t trx_id)
dfield_set_data(&dfield, foreign->id, id_len);
dict_index_copy_types(&tuple, sys_index, 1);
+ pcur.btr_cur.page_cur.index = sys_index;
mem_heap_t* heap = nullptr;
- dberr_t err = btr_pcur_open_on_user_rec(sys_index, &tuple, PAGE_CUR_GE,
+ dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
if (err != DB_SUCCESS) {
goto func_exit;
@@ -2877,11 +2884,12 @@ dict_load_foreign(
};
dfield_set_data(&dfield, id.data(), id.size());
dict_index_copy_types(&tuple, sys_index, 1);
+ pcur.btr_cur.page_cur.index = sys_index;
mtr.start();
mem_heap_t* heap = nullptr;
- dberr_t err = btr_pcur_open_on_user_rec(sys_index, &tuple, PAGE_CUR_GE,
+ dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
if (err != DB_SUCCESS) {
goto err_exit;
@@ -3090,8 +3098,9 @@ start_load:
mtr.start();
dfield_set_data(&dfield, table_name, strlen(table_name));
dict_index_copy_types(&tuple, sec_index, 1);
+ pcur.btr_cur.page_cur.index = sec_index;
- dberr_t err = btr_pcur_open_on_user_rec(sec_index, &tuple, PAGE_CUR_GE,
+ dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
if (err != DB_SUCCESS) {
DBUG_RETURN(err);
@@ -3192,7 +3201,6 @@ next_rec:
load_next_index:
mtr.commit();
- ut_free(pcur.old_rec_buf);
if ((sec_index = dict_table_get_next_index(sec_index))) {
/* Switch to scan index on REF_NAME, fk_max_recusive_level
@@ -3202,5 +3210,6 @@ load_next_index:
goto start_load;
}
+ ut_free(pcur.old_rec_buf);
DBUG_RETURN(DB_SUCCESS);
}
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 84fac55a304..c7355f85c2e 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -1560,6 +1560,96 @@ empty_table:
return err;
}
+/** Open a cursor at the first page in a tree level.
+@param page_cur cursor
+@param level level to search for (0=leaf)
+@param mtr mini-transaction */
+static dberr_t page_cur_open_level(page_cur_t *page_cur, ulint level,
+ mtr_t *mtr)
+{
+ mem_heap_t *heap= nullptr;
+ rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_offs *offsets= offsets_;
+ dberr_t err;
+
+ dict_index_t *const index= page_cur->index;
+
+ rec_offs_init(offsets_);
+ ut_ad(level != ULINT_UNDEFINED);
+ ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_SX_LOCK));
+ ut_ad(mtr->get_savepoint() == 1);
+
+ uint32_t page= index->page;
+
+ for (ulint height = ULINT_UNDEFINED;; height--)
+ {
+ buf_block_t* block=
+ btr_block_get(*index, page, RW_S_LATCH,
+ !height && !index->is_clust(), mtr, &err);
+ if (!block)
+ break;
+
+ const uint32_t l= btr_page_get_level(block->page.frame);
+
+ if (height == ULINT_UNDEFINED)
+ {
+ ut_ad(!heap);
+ /* We are in the root node */
+ height= l;
+ if (UNIV_UNLIKELY(height < level))
+ return DB_CORRUPTION;
+ }
+ else if (UNIV_UNLIKELY(height != l) || page_has_prev(block->page.frame))
+ {
+ err= DB_CORRUPTION;
+ break;
+ }
+
+ page_cur_set_before_first(block, page_cur);
+
+ if (height == level)
+ break;
+
+ ut_ad(height);
+
+ if (!page_cur_move_to_next(page_cur))
+ {
+ err= DB_CORRUPTION;
+ break;
+ }
+
+ offsets= rec_get_offsets(page_cur->rec, index, offsets, 0, ULINT_UNDEFINED,
+ &heap);
+ page= btr_node_ptr_get_child_page_no(page_cur->rec, offsets);
+ }
+
+ if (UNIV_LIKELY_NULL(heap))
+ mem_heap_free(heap);
+
+ /* Release all page latches except the one on the desired page. */
+ const auto end= mtr->get_savepoint();
+ if (end > 1)
+ mtr->rollback_to_savepoint(1, end - 1);
+
+ return err;
+}
+
+/** Open a cursor at the first page in a tree level.
+@param page_cur cursor
+@param level level to search for (0=leaf)
+@param mtr mini-transaction
+@param index index tree */
+static dberr_t btr_pcur_open_level(btr_pcur_t *pcur, ulint level, mtr_t *mtr,
+ dict_index_t *index)
+{
+ pcur->latch_mode= BTR_SEARCH_TREE;
+ pcur->search_mode= PAGE_CUR_G;
+ pcur->pos_state= BTR_PCUR_IS_POSITIONED;
+ pcur->btr_cur.page_cur.index= index;
+ return page_cur_open_level(&pcur->btr_cur.page_cur, level, mtr);
+}
+
+
/* @{ Pseudo code about the relation between the following functions
let N = N_SAMPLE_PAGES(index)
@@ -1616,7 +1706,8 @@ dict_stats_analyze_index_level(
DEBUG_PRINTF(" %s(table=%s, index=%s, level=" ULINTPF ")\n",
__func__, index->table->name, index->name, level);
- ut_ad(mtr->memo_contains(index->lock, MTR_MEMO_SX_LOCK));
+ *total_recs = 0;
+ *total_pages = 0;
n_uniq = dict_index_get_n_unique(index);
@@ -1649,9 +1740,7 @@ dict_stats_analyze_index_level(
/* Position pcur on the leftmost record on the leftmost page
on the desired level. */
- if (btr_pcur_open_at_index_side(
- true, index, BTR_SEARCH_TREE_ALREADY_S_LATCHED,
- &pcur, true, level, mtr) != DB_SUCCESS
+ if (btr_pcur_open_level(&pcur, level, mtr, index) != DB_SUCCESS
|| !btr_pcur_move_to_next_on_page(&pcur)) {
goto func_exit;
}
@@ -1661,21 +1750,10 @@ dict_stats_analyze_index_level(
/* The page must not be empty, except when
it is the root page (and the whole index is empty). */
ut_ad(btr_pcur_is_on_user_rec(&pcur) || page_is_leaf(page));
- ut_ad(btr_pcur_get_rec(&pcur)
- == page_rec_get_next_const(page_get_infimum_rec(page)));
prev_rec = NULL;
prev_rec_is_copied = false;
- /* no records by default */
- *total_recs = 0;
-
- *total_pages = 0;
-
- if (page_has_prev(page) || btr_page_get_level(page) != level) {
- goto func_exit;
- }
-
if (REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
btr_pcur_get_rec(&pcur), page_is_comp(page))) {
ut_ad(btr_pcur_is_on_user_rec(&pcur));
@@ -1728,10 +1806,7 @@ dict_stats_analyze_index_level(
if (level == 0
&& !srv_stats_include_delete_marked
- && rec_get_deleted_flag(
- rec,
- page_is_comp(btr_pcur_get_page(&pcur)))) {
-
+ && rec_get_deleted_flag(rec, page_rec_is_comp(rec))) {
if (rec_is_last_on_page
&& !prev_rec_is_copied
&& prev_rec != NULL) {
@@ -1811,7 +1886,7 @@ dict_stats_analyze_index_level(
records on this level at some point we will jump from
one page to the next and then rec and prev_rec will
be on different pages and
- btr_pcur_move_to_next_user_rec() will release the
+ btr_cur_move_to_next_user_rec() will release the
latch on the page that prev_rec is on */
prev_rec = rec_copy_prefix_to_buf(
rec, index, n_uniq,
@@ -1820,7 +1895,7 @@ dict_stats_analyze_index_level(
} else {
/* still on the same page, the next call to
- btr_pcur_move_to_next_user_rec() will not jump
+ btr_cur_move_to_next_user_rec() will not jump
on the next page, we can simply assign pointers
instead of copying the records like above */
@@ -1891,7 +1966,6 @@ dict_stats_analyze_index_level(
}
#endif /* UNIV_STATS_DEBUG */
- btr_leaf_page_release(btr_pcur_get_block(&pcur), BTR_SEARCH_LEAF, mtr);
func_exit:
ut_free(prev_rec_buf);
mem_heap_free(heap);
@@ -2280,7 +2354,6 @@ dict_stats_analyze_index_for_n_prefix(
n_prefix, n_diff_data->n_diff_on_level);
#endif
- ut_ad(mtr->memo_contains(index->lock, MTR_MEMO_SX_LOCK));
ut_ad(n_diff_data->level);
/* Position pcur on the leftmost record on the leftmost page
@@ -2289,9 +2362,7 @@ dict_stats_analyze_index_for_n_prefix(
n_diff_data->n_diff_all_analyzed_pages = 0;
n_diff_data->n_external_pages_sum = 0;
- if (btr_pcur_open_at_index_side(true, index,
- BTR_SEARCH_TREE_ALREADY_S_LATCHED,
- &pcur, true, n_diff_data->level, mtr)
+ if (btr_pcur_open_level(&pcur, n_diff_data->level, mtr, index)
!= DB_SUCCESS
|| !btr_pcur_move_to_next_on_page(&pcur)) {
return;
@@ -2680,6 +2751,7 @@ empty_index:
mtr.commit();
mtr.start();
mtr_sx_lock_index(index, &mtr);
+ ut_ad(mtr.get_savepoint() == 1);
buf_block_t *root = btr_root_block_get(index, RW_S_LATCH,
&mtr, &err);
if (!root || root_level != btr_page_get_level(root->page.frame)
@@ -2695,7 +2767,7 @@ empty_index:
break;
}
- mtr.memo_release(root, MTR_MEMO_PAGE_S_FIX);
+ mtr.rollback_to_savepoint(1);
/* check whether we should pick the current level;
we pick level 1 even if it does not have enough
@@ -2757,6 +2829,7 @@ empty_index:
break;
}
+ mtr.rollback_to_savepoint(1);
dict_stats_analyze_index_level(index,
level,
n_diff_on_level,
@@ -2764,7 +2837,7 @@ empty_index:
&total_pages,
n_diff_boundaries,
&mtr);
-
+ mtr.rollback_to_savepoint(1);
level_is_analyzed = true;
if (level == 1
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index 0a2026efa33..067aca49b4c 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -1831,7 +1831,6 @@ fil_crypt_rotate_page(
} else {
/* If block read failed mtr memo and log should be empty. */
ut_ad(!mtr.has_modifications());
- ut_ad(!mtr.is_dirty());
ut_ad(mtr.is_empty());
mtr.commit();
}
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 2707751a6f6..acbe2e453a4 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -3347,7 +3347,6 @@ fts_add_doc_by_id(
is_id_cluster = (clust_index == fts_id_index);
mtr_start(&mtr);
- btr_pcur_init(&pcur);
/* Search based on Doc ID. Here, we'll need to consider the case
when there is no primary index on Doc ID */
@@ -3358,9 +3357,10 @@ fts_add_doc_by_id(
mach_write_to_8((byte*) &temp_doc_id, doc_id);
dfield_set_data(dfield, &temp_doc_id, sizeof(temp_doc_id));
+ pcur.btr_cur.page_cur.index = fts_id_index;
/* If we have a match, add the data to doc structure */
- if (btr_pcur_open_with_no_init(fts_id_index, tuple, PAGE_CUR_LE,
+ if (btr_pcur_open_with_no_init(tuple, PAGE_CUR_LE,
BTR_SEARCH_LEAF, &pcur, &mtr)
== DB_SUCCESS
&& btr_pcur_get_low_match(&pcur) == 1) {
@@ -3387,7 +3387,6 @@ fts_add_doc_by_id(
dtuple_t* clust_ref;
ulint n_fields;
- btr_pcur_init(&clust_pcur);
n_fields = dict_index_get_n_unique(clust_index);
clust_ref = dtuple_create(heap, n_fields);
@@ -3395,8 +3394,9 @@ fts_add_doc_by_id(
row_build_row_ref_in_tuple(
clust_ref, rec, fts_id_index, NULL);
+ clust_pcur.btr_cur.page_cur.index = clust_index;
- if (btr_pcur_open_with_no_init(clust_index, clust_ref,
+ if (btr_pcur_open_with_no_init(clust_ref,
PAGE_CUR_LE,
BTR_SEARCH_LEAF,
&clust_pcur, &mtr)
@@ -3552,12 +3552,11 @@ fts_get_max_doc_id(
ut_ad(innobase_strcasecmp(FTS_DOC_ID_COL_NAME, dfield->name) == 0);
#endif
- mtr_start(&mtr);
+ mtr.start();
/* fetch the largest indexes value */
- if (btr_pcur_open_at_index_side(false, index, BTR_SEARCH_LEAF, &pcur,
- true, 0, &mtr) != DB_SUCCESS) {
- } else if (!page_is_empty(btr_pcur_get_page(&pcur))) {
+ if (pcur.open_leaf(false, index, BTR_SEARCH_LEAF, &mtr) == DB_SUCCESS
+ && !page_is_empty(btr_pcur_get_page(&pcur))) {
const rec_t* rec = NULL;
do {
@@ -3576,7 +3575,7 @@ fts_get_max_doc_id(
}
func_exit:
- mtr_commit(&mtr);
+ mtr.commit();
return(doc_id);
}
diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc
index 88723ce5e8a..59d77c9c5fc 100644
--- a/storage/innobase/gis/gis0rtree.cc
+++ b/storage/innobase/gis/gis0rtree.cc
@@ -70,7 +70,7 @@ rtr_page_split_initialize_nodes(
block = btr_cur_get_block(cursor);
page = buf_block_get_frame(block);
- n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
+ n_uniq = dict_index_get_n_unique_in_tree(cursor->index());
n_recs = ulint(page_get_n_recs(page)) + 1;
@@ -88,8 +88,8 @@ rtr_page_split_initialize_nodes(
rec = page_rec_get_next(page_get_infimum_rec(page));
const ulint n_core = page_is_leaf(page)
- ? cursor->index->n_core_fields : 0;
- *offsets = rec_get_offsets(rec, cursor->index, *offsets, n_core,
+ ? cursor->index()->n_core_fields : 0;
+ *offsets = rec_get_offsets(rec, cursor->index(), *offsets, n_core,
n_uniq, &heap);
source_cur = rec_get_nth_field(rec, *offsets, 0, &len);
@@ -101,7 +101,7 @@ rtr_page_split_initialize_nodes(
memcpy(cur->coords, source_cur, DATA_MBR_LEN);
rec = page_rec_get_next(rec);
- *offsets = rec_get_offsets(rec, cursor->index, *offsets,
+ *offsets = rec_get_offsets(rec, cursor->index(), *offsets,
n_core, n_uniq, &heap);
source_cur = rec_get_nth_field(rec, *offsets, 0, &len);
}
@@ -111,9 +111,9 @@ rtr_page_split_initialize_nodes(
dtuple_get_nth_field(tuple, 0)));
cur->coords = reserve_coords(buf_pos, SPDIMS);
rec = (byte*) mem_heap_alloc(
- heap, rec_get_converted_size(cursor->index, tuple, 0));
+ heap, rec_get_converted_size(cursor->index(), tuple, 0));
- rec = rec_convert_dtuple_to_rec(rec, cursor->index, tuple, 0);
+ rec = rec_convert_dtuple_to_rec(rec, cursor->index(), tuple, 0);
cur->key = rec;
memcpy(cur->coords, source_cur, DATA_MBR_LEN);
@@ -200,7 +200,7 @@ rtr_update_mbr_field(
rec_t* new_rec, /*!< in: rec to use */
mtr_t* mtr) /*!< in: mtr */
{
- dict_index_t* index = cursor->index;
+ dict_index_t* index = cursor->index();
mem_heap_t* heap;
page_t* page;
rec_t* rec;
@@ -245,6 +245,7 @@ rtr_update_mbr_field(
/* We need to remember the child page no of cursor2, since page could be
reorganized or insert a new rec before it. */
if (cursor2) {
+ ut_ad(cursor2->index() == index);
rec_t* del_rec = btr_cur_get_rec(cursor2);
offsets2 = rec_get_offsets(btr_cur_get_rec(cursor2),
index, NULL, 0,
@@ -268,7 +269,7 @@ rtr_update_mbr_field(
if (!btr_cur_update_alloc_zip(
page_zip,
btr_cur_get_page_cur(cursor),
- index, offsets,
+ offsets,
rec_offs_size(offsets),
false, mtr)) {
@@ -321,7 +322,7 @@ rtr_update_mbr_field(
offsets2));
page_cur_delete_rec(btr_cur_get_page_cur(cursor2),
- index, offsets2, mtr);
+ offsets2, mtr);
}
} else if (page_get_n_recs(page) == 1) {
/* When there's only one rec in the page, we do insert/delete to
@@ -352,9 +353,10 @@ rtr_update_mbr_field(
ut_ad(old_rec != insert_rec);
page_cur_position(old_rec, block, &page_cur);
+ page_cur.index = index;
offsets2 = rec_get_offsets(old_rec, index, NULL, n_core,
ULINT_UNDEFINED, &heap);
- page_cur_delete_rec(&page_cur, index, offsets2, mtr);
+ page_cur_delete_rec(&page_cur, offsets2, mtr);
} else {
update_mbr:
@@ -366,8 +368,7 @@ update_mbr:
/* Delete the rec which cursor point to. */
next_rec = page_rec_get_next(rec);
- page_cur_delete_rec(btr_cur_get_page_cur(cursor),
- index, offsets, mtr);
+ page_cur_delete_rec(&cursor->page_cur, offsets, mtr);
if (!ins_suc) {
ut_ad(rec_info & REC_INFO_MIN_REC_FLAG);
@@ -400,13 +401,12 @@ update_mbr:
== btr_node_ptr_get_child_page_no(cur2_rec,
offsets2));
page_cur_delete_rec(btr_cur_get_page_cur(cursor2),
- index, offsets2, mtr);
+ offsets2, mtr);
cursor2 = NULL;
}
/* Insert the new rec. */
- if (page_cur_search_with_match(block, index, node_ptr,
- PAGE_CUR_LE,
+ if (page_cur_search_with_match(node_ptr, PAGE_CUR_LE,
&up_match, &low_match,
btr_cur_get_page_cur(cursor),
NULL)) {
@@ -424,7 +424,7 @@ update_mbr:
} else if (ins_suc) {
ut_ad(err == DB_FAIL);
err = btr_page_reorganize(btr_cur_get_page_cur(cursor),
- index, mtr);
+ mtr);
if (err == DB_SUCCESS) {
err = btr_cur_optimistic_insert(
flags, cursor, &insert_offsets, &heap,
@@ -505,7 +505,7 @@ update_mbr:
ut_ad(cur2_pno == del_page_no && cur2_rec != insert_rec);
page_cur_delete_rec(btr_cur_get_page_cur(cursor2),
- index, offsets2, mtr);
+ offsets2, mtr);
}
if (!ins_suc) {
@@ -556,7 +556,6 @@ rtr_adjust_upper_level(
{
ulint page_no;
ulint new_page_no;
- dict_index_t* index = sea_cur->index;
btr_cur_t cursor;
rec_offs* offsets;
mem_heap_t* heap;
@@ -570,9 +569,10 @@ rtr_adjust_upper_level(
/* Create a memory heap where the data tuple is stored */
heap = mem_heap_create(1024);
- cursor.init();
cursor.thr = sea_cur->thr;
+ cursor.page_cur.index = sea_cur->index();
+ cursor.page_cur.block = block;
/* Get the level of the split pages */
level = btr_page_get_level(buf_block_get_frame(block));
@@ -584,8 +584,7 @@ rtr_adjust_upper_level(
/* Set new mbr for the old page on the upper level. */
/* Look up the index for the node pointer to page */
- offsets = rtr_page_get_father_block(
- NULL, heap, index, block, mtr, sea_cur, &cursor);
+ offsets = rtr_page_get_father_block(NULL, heap, mtr, sea_cur, &cursor);
page_cursor = btr_cur_get_page_cur(&cursor);
@@ -607,10 +606,9 @@ rtr_adjust_upper_level(
page_get_infimum_rec(new_block->page.frame))) {
/* Insert the node for the new page. */
node_ptr_upper = rtr_index_build_node_ptr(
- index, new_mbr, first, new_page_no, heap);
+ sea_cur->index(), new_mbr, first, new_page_no, heap);
ulint up_match = 0, low_match = 0;
- err = page_cur_search_with_match(btr_cur_get_block(&cursor),
- index, node_ptr_upper,
+ err = page_cur_search_with_match(node_ptr_upper,
PAGE_CUR_LE,
&up_match, &low_match,
btr_cur_get_page_cur(&cursor),
@@ -660,7 +658,7 @@ rtr_adjust_upper_level(
mem_heap_free(heap);
- ut_ad(block->zip_size() == index->table->space->zip_size());
+ ut_ad(block->zip_size() == sea_cur->index()->table->space->zip_size());
if (err != DB_SUCCESS) {
return err;
@@ -670,7 +668,7 @@ rtr_adjust_upper_level(
if (next_page_no == FIL_NULL) {
} else if (buf_block_t* next_block =
- btr_block_get(*index, next_page_no, RW_X_LATCH,
+ btr_block_get(*sea_cur->index(), next_page_no, RW_X_LATCH,
false, mtr, &err)) {
if (UNIV_UNLIKELY(memcmp_aligned<4>(next_block->page.frame
+ FIL_PAGE_PREV,
@@ -740,6 +738,7 @@ rtr_split_page_move_rec_list(
page_cur_set_before_first(block, &page_cursor);
page_cur_set_before_first(new_block, &new_page_cursor);
+ page_cursor.index = new_page_cursor.index = index;
page = buf_block_get_frame(block);
new_page = buf_block_get_frame(new_block);
@@ -774,7 +773,7 @@ rtr_split_page_move_rec_list(
rec = page_cur_insert_rec_low(
&new_page_cursor,
- index, cur_split_node->key, offsets, mtr);
+ cur_split_node->key, offsets, mtr);
if (UNIV_UNLIKELY
(!rec
@@ -841,8 +840,7 @@ rtr_split_page_move_rec_list(
page_cur_get_rec(&page_cursor), index,
offsets, n_core, ULINT_UNDEFINED,
&heap);
- page_cur_delete_rec(&page_cursor,
- index, offsets, mtr);
+ page_cur_delete_rec(&page_cursor, offsets, mtr);
}
}
@@ -877,7 +875,6 @@ rtr_page_split_and_insert(
buf_block_t* new_block;
page_zip_des_t* page_zip;
page_zip_des_t* new_page_zip;
- buf_block_t* insert_block;
page_cur_t* page_cursor;
rec_t* rec = 0;
ulint n_recs;
@@ -906,12 +903,10 @@ func_start:
mem_heap_empty(*heap);
*offsets = NULL;
- ut_ad(mtr->memo_contains_flagged(&cursor->index->lock, MTR_MEMO_X_LOCK
- | MTR_MEMO_SX_LOCK));
- ut_ad(!dict_index_is_online_ddl(cursor->index)
- || (flags & BTR_CREATE_FLAG)
- || dict_index_is_clust(cursor->index));
- ut_ad(cursor->index->lock.have_u_or_x());
+ ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock,
+ MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK));
+ ut_ad(!dict_index_is_online_ddl(cursor->index()));
+ ut_ad(cursor->index()->lock.have_u_or_x());
block = btr_cur_get_block(cursor);
page = buf_block_get_frame(block);
@@ -954,7 +949,7 @@ corrupted:
}
#endif
- insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
+ insert_size = rec_get_converted_size(cursor->index(), tuple, n_ext);
total_data = page_get_data_size(page) + insert_size;
first_rec_group = split_rtree_node(rtr_split_node_array,
static_cast<int>(n_recs),
@@ -965,7 +960,7 @@ corrupted:
/* Allocate a new page to the index */
const uint16_t page_level = btr_page_get_level(page);
- new_block = btr_page_alloc(cursor->index, page_id.page_no() + 1,
+ new_block = btr_page_alloc(cursor->index(), page_id.page_no() + 1,
FSP_UP, page_level, mtr, mtr, err);
if (UNIV_UNLIKELY(!new_block)) {
return nullptr;
@@ -977,7 +972,7 @@ corrupted:
to contain FIL_NULL in FIL_PAGE_PREV at this stage. */
memset_aligned<4>(new_block->page.frame + FIL_PAGE_PREV, 0, 4);
}
- btr_page_create(new_block, new_page_zip, cursor->index,
+ btr_page_create(new_block, new_page_zip, cursor->index(),
page_level, mtr);
new_page = buf_block_get_frame(new_block);
@@ -985,7 +980,7 @@ corrupted:
/* Set new ssn to the new page and page. */
page_set_ssn_id(new_block, new_page_zip, current_ssn, mtr);
- next_ssn = rtr_get_new_ssn_id(cursor->index);
+ next_ssn = rtr_get_new_ssn_id(cursor->index());
page_set_ssn_id(block, page_zip, next_ssn, mtr);
@@ -998,7 +993,7 @@ corrupted:
|| (*err = rtr_split_page_move_rec_list(rtr_split_node_array,
first_rec_group,
new_block, block,
- first_rec, cursor->index,
+ first_rec, cursor->index(),
*heap, mtr))) {
if (*err != DB_FAIL) {
return nullptr;
@@ -1021,7 +1016,7 @@ corrupted:
ut_a(new_page_zip);
page_zip_copy_recs(new_block,
- page_zip, page, cursor->index, mtr);
+ page_zip, page, cursor->index(), mtr);
page_cursor = btr_cur_get_page_cur(cursor);
@@ -1056,7 +1051,7 @@ corrupted:
lock_rtr_move_rec_list(new_block, block, rec_move, moved);
const ulint n_core = page_level
- ? 0 : cursor->index->n_core_fields;
+ ? 0 : cursor->index()->n_core_fields;
/* Delete recs in first group from the new page. */
for (cur_split_node = rtr_split_node_array;
@@ -1076,11 +1071,11 @@ corrupted:
*offsets = rec_get_offsets(
page_cur_get_rec(page_cursor),
- cursor->index, *offsets, n_core,
+ cursor->index(), *offsets, n_core,
ULINT_UNDEFINED, heap);
page_cur_delete_rec(page_cursor,
- cursor->index, *offsets, mtr);
+ *offsets, mtr);
n++;
}
}
@@ -1093,32 +1088,30 @@ corrupted:
block, page_cursor);
*offsets = rec_get_offsets(
page_cur_get_rec(page_cursor),
- cursor->index, *offsets, n_core,
+ page_cursor->index, *offsets, n_core,
ULINT_UNDEFINED, heap);
- page_cur_delete_rec(page_cursor,
- cursor->index, *offsets, mtr);
+ page_cur_delete_rec(page_cursor, *offsets,
+ mtr);
}
}
#ifdef UNIV_GIS_DEBUG
- ut_ad(page_validate(new_page, cursor->index));
- ut_ad(page_validate(page, cursor->index));
+ ut_ad(page_validate(new_page, cursor->index()));
+ ut_ad(page_validate(page, cursor->index()));
#endif
}
/* Insert the new rec to the proper page. */
cur_split_node = end_split_node - 1;
- if (cur_split_node->n_node != first_rec_group) {
- insert_block = new_block;
- } else {
- insert_block = block;
- }
/* Reposition the cursor for insert and try insertion */
page_cursor = btr_cur_get_page_cur(cursor);
+ page_cursor->block = cur_split_node->n_node != first_rec_group
+ ? new_block : block;
+
ulint up_match = 0, low_match = 0;
- if (page_cur_search_with_match(insert_block, cursor->index, tuple,
+ if (page_cur_search_with_match(tuple,
PAGE_CUR_LE, &up_match, &low_match,
page_cursor, nullptr)) {
goto corrupted;
@@ -1133,7 +1126,7 @@ corrupted:
goto after_insert; }
);
- rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
+ rec = page_cur_tuple_insert(page_cursor, tuple,
offsets, heap, n_ext, mtr);
/* If insert did not fit, try page reorganization.
@@ -1141,14 +1134,13 @@ corrupted:
attempted this already. */
if (rec == NULL) {
if (!is_page_cur_get_page_zip(page_cursor)
- && btr_page_reorganize(page_cursor, cursor->index, mtr)) {
+ && btr_page_reorganize(page_cursor, mtr)) {
rec = page_cur_tuple_insert(page_cursor, tuple,
- cursor->index, offsets,
+ offsets,
heap, n_ext, mtr);
}
- /* If insert fail, we will try to split the insert_block
- again. */
+ /* If insert fail, we will try to split the block again. */
}
#ifdef UNIV_DEBUG
@@ -1156,8 +1148,8 @@ after_insert:
#endif
/* Calculate the mbr on the upper half-page, and the mbr on
original page. */
- rtr_page_cal_mbr(cursor->index, block, &mbr, *heap);
- rtr_page_cal_mbr(cursor->index, new_block, &new_mbr, *heap);
+ rtr_page_cal_mbr(cursor->index(), block, &mbr, *heap);
+ rtr_page_cal_mbr(cursor->index(), new_block, &new_mbr, *heap);
prdt.data = &mbr;
new_prdt.data = &new_mbr;
@@ -1175,7 +1167,8 @@ after_insert:
/* Save the new ssn to the root page, since we need to reinit
the first ssn value from it after restart server. */
- root_block = btr_root_block_get(cursor->index, RW_SX_LATCH, mtr, err);
+ root_block = btr_root_block_get(cursor->index(), RW_SX_LATCH,
+ mtr, err);
if (UNIV_UNLIKELY(!root_block)) {
return nullptr;
}
@@ -1187,8 +1180,8 @@ after_insert:
again. */
if (!rec) {
/* We play safe and reset the free bits for new_page */
- if (!dict_index_is_clust(cursor->index)
- && !cursor->index->table->is_temporary()) {
+ if (!dict_index_is_clust(cursor->index())
+ && !cursor->index()->table->is_temporary()) {
ibuf_reset_free_bits(new_block);
ibuf_reset_free_bits(block);
}
@@ -1205,16 +1198,16 @@ after_insert:
if (UNIV_UNLIKELY(!i_rec)) {
goto corrupted;
}
- btr_cur_position(cursor->index, i_rec, block, cursor);
+ btr_cur_position(cursor->index(), i_rec, block, cursor);
goto func_start;
}
#ifdef UNIV_GIS_DEBUG
- ut_ad(page_validate(buf_block_get_frame(block), cursor->index));
- ut_ad(page_validate(buf_block_get_frame(new_block), cursor->index));
+ ut_ad(page_validate(buf_block_get_frame(block), cursor->index()));
+ ut_ad(page_validate(buf_block_get_frame(new_block), cursor->index()));
- ut_ad(!rec || rec_offs_validate(rec, cursor->index, *offsets));
+ ut_ad(!rec || rec_offs_validate(rec, cursor->index(), *offsets));
#endif
MONITOR_INC(MONITOR_INDEX_SPLIT);
@@ -1234,14 +1227,13 @@ rtr_ins_enlarge_mbr(
rtr_mbr_t new_mbr;
buf_block_t* block;
mem_heap_t* heap;
- dict_index_t* index = btr_cur->index;
page_cur_t* page_cursor;
rec_offs* offsets;
node_visit_t* node_visit;
btr_cur_t cursor;
page_t* page;
- ut_ad(dict_index_is_spatial(index));
+ ut_ad(btr_cur->index()->is_spatial());
/* If no rtr_info or rtree is one level tree, return. */
if (!btr_cur->rtr_info || btr_cur->tree_height == 1) {
@@ -1269,20 +1261,20 @@ rtr_ins_enlarge_mbr(
}
/* Calculate the mbr of the child page. */
- rtr_page_cal_mbr(index, block, &new_mbr, heap);
+ rtr_page_cal_mbr(page_cursor->index, block, &new_mbr, heap);
/* Get father block. */
- cursor.init();
+ cursor.page_cur.index = page_cursor->index;
+ cursor.page_cur.block = block;
offsets = rtr_page_get_father_block(
- NULL, heap, index, block, mtr, btr_cur, &cursor);
+ NULL, heap, mtr, btr_cur, &cursor);
page = buf_block_get_frame(block);
/* Update the mbr field of the rec. */
rtr_update_mbr_field(&cursor, offsets, NULL, page,
&new_mbr, NULL, mtr);
- page_cursor = btr_cur_get_page_cur(&cursor);
- block = page_cur_get_block(page_cursor);
+ block = btr_cur_get_block(&cursor);
}
mem_heap_free(heap);
@@ -1338,6 +1330,7 @@ rtr_page_copy_rec_list_end_no_locks(
return DB_CORRUPTION;
}
page_cur_position(cur_rec, new_block, &page_cur);
+ page_cur.index = index;
/* Copy records from the original page to the new page */
while (!page_cur_is_after_last(&cur1)) {
@@ -1399,7 +1392,7 @@ move_to_prev:
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
ULINT_UNDEFINED, &heap);
- ins_rec = page_cur_insert_rec_low(&page_cur, index,
+ ins_rec = page_cur_insert_rec_low(&page_cur,
cur1_rec, offsets1, mtr);
if (UNIV_UNLIKELY(!ins_rec || moved >= max_move)) {
return DB_CORRUPTION;
@@ -1461,6 +1454,7 @@ rtr_page_copy_rec_list_start_no_locks(
return DB_CORRUPTION;
}
page_cur_position(cur_rec, new_block, &page_cur);
+ page_cur.index = index;
while (page_cur_get_rec(&cur1) != rec) {
rec_t* cur1_rec = page_cur_get_rec(&cur1);
@@ -1522,7 +1516,7 @@ move_to_prev:
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
ULINT_UNDEFINED, &heap);
- ins_rec = page_cur_insert_rec_low(&page_cur, index,
+ ins_rec = page_cur_insert_rec_low(&page_cur,
cur1_rec, offsets1, mtr);
if (UNIV_UNLIKELY(!ins_rec || moved >= max_move)) {
return DB_CORRUPTION;
@@ -1560,7 +1554,7 @@ rtr_merge_mbr_changed(
ulint len;
bool changed = false;
- ut_ad(dict_index_is_spatial(cursor->index));
+ ut_ad(cursor->index()->is_spatial());
rec = btr_cur_get_rec(cursor);
@@ -1640,11 +1634,11 @@ rtr_check_same_block(
btr_cur_t* cursor, /*!< in/out: position at the parent entry
pointing to the child if successful */
buf_block_t* parentb,/*!< in: parent page to check */
- buf_block_t* childb, /*!< in: child Page */
mem_heap_t* heap) /*!< in: memory heap */
{
- ulint page_no = childb->page.id().page_no();
+ const uint32_t page_no =
+ btr_cur_get_block(cursor)->page.id().page_no();
rec_offs* offsets;
rec_t* rec = page_get_infimum_rec(parentb->page.frame);
diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc
index 78d0a5b9705..207d49abeba 100644
--- a/storage/innobase/gis/gis0sea.cc
+++ b/storage/innobase/gis/gis0sea.cc
@@ -95,14 +95,13 @@ rtr_pcur_getnext_from_path(
/*!< in: index tree locked */
mtr_t* mtr) /*!< in: mtr */
{
- dict_index_t* index = btr_cur->index;
+ dict_index_t* index = btr_cur->index();
bool found = false;
page_cur_t* page_cursor;
ulint level = 0;
node_visit_t next_rec;
rtr_info_t* rtr_info = btr_cur->rtr_info;
node_seq_t page_ssn;
- ulint my_latch_mode;
ulint skip_parent = false;
bool new_split = false;
bool for_delete = false;
@@ -115,7 +114,7 @@ rtr_pcur_getnext_from_path(
ut_ad(dtuple_get_n_fields_cmp(tuple));
- my_latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
+ const auto my_latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
for_delete = latch_mode & BTR_RTREE_DELETE_MARK;
for_undo_ins = latch_mode & BTR_RTREE_UNDO_INS;
@@ -299,6 +298,7 @@ rtr_pcur_getnext_from_path(
page_cursor = btr_cur_get_page_cur(btr_cur);
page_cursor->rec = NULL;
+ page_cursor->block = block;
if (mode == PAGE_CUR_RTREE_LOCATE) {
if (target_level == 0 && level == 0) {
@@ -307,7 +307,7 @@ rtr_pcur_getnext_from_path(
found = false;
if (!page_cur_search_with_match(
- block, index, tuple, PAGE_CUR_LE,
+ tuple, PAGE_CUR_LE,
&up_match, &low_match,
btr_cur_get_page_cur(btr_cur), nullptr)
&& low_match
@@ -351,17 +351,12 @@ rtr_pcur_getnext_from_path(
BTR_PCUR_IS_POSITIONED;
r_cursor->latch_mode = my_latch_mode;
btr_pcur_store_position(r_cursor, mtr);
-#ifdef UNIV_DEBUG
- ulint num_stored =
- rtr_store_parent_path(
- block, btr_cur,
- rw_latch, level, mtr);
- ut_ad(num_stored > 0);
-#else
+ ut_d(ulint num_stored =)
rtr_store_parent_path(
- block, btr_cur, rw_latch,
+ block, btr_cur,
+ btr_latch_mode(rw_latch),
level, mtr);
-#endif /* UNIV_DEBUG */
+ ut_ad(num_stored > 0);
}
}
} else {
@@ -443,11 +438,11 @@ rtr_pcur_getnext_from_path(
const rec_t* rec = btr_cur_get_rec(btr_cur);
- if (page_rec_is_infimum(rec) || page_rec_is_supremum(rec)) {
- mtr_commit(mtr);
- mtr_start(mtr);
+ if (!page_rec_is_user_rec(rec)) {
+ mtr->commit();
+ mtr->start();
} else if (!index_locked) {
- mtr_memo_release(mtr, &index->lock, MTR_MEMO_X_LOCK);
+ mtr->release(index->lock);
}
return(found);
@@ -521,7 +516,7 @@ bool
rtr_pcur_open(
dict_index_t* index, /*!< in: index */
const dtuple_t* tuple, /*!< in: tuple on which search done */
- ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
+ btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
mtr_t* mtr) /*!< in: mtr */
{
@@ -539,6 +534,7 @@ rtr_pcur_open(
/* Search with the tree cursor */
btr_cur_t* btr_cursor = btr_pcur_get_btr_cur(cursor);
+ btr_cursor->page_cur.index = index;
btr_cursor->rtr_info = rtr_create_rtr_info(false, false,
btr_cursor, index);
@@ -554,7 +550,7 @@ rtr_pcur_open(
mtr->lock_upgrade(index->lock);
}
- if (btr_cur_search_to_nth_level(index, 0, tuple, PAGE_CUR_RTREE_LOCATE,
+ if (btr_cur_search_to_nth_level(0, tuple, PAGE_CUR_RTREE_LOCATE,
latch_mode,
btr_cursor, mtr) != DB_SUCCESS) {
return true;
@@ -606,24 +602,16 @@ rtr_pcur_open(
}
/* Get the rtree page father.
-@param[in] index rtree index
-@param[in] block child page in the index
@param[in,out] mtr mtr
@param[in] sea_cur search cursor, contains information
about parent nodes in search
@param[out] cursor cursor on node pointer record,
its page x-latched
@return whether the cursor was successfully positioned */
-bool
-rtr_page_get_father(
- dict_index_t* index,
- buf_block_t* block,
- mtr_t* mtr,
- btr_cur_t* sea_cur,
- btr_cur_t* cursor)
+bool rtr_page_get_father(mtr_t *mtr, btr_cur_t *sea_cur, btr_cur_t *cursor)
{
mem_heap_t *heap = mem_heap_create(100);
- rec_offs *offsets= rtr_page_get_father_block(nullptr, heap, index, block,
+ rec_offs *offsets= rtr_page_get_father_block(nullptr, heap,
mtr, sea_cur, cursor);
mem_heap_free(heap);
return offsets != nullptr;
@@ -634,7 +622,6 @@ MY_ATTRIBUTE((warn_unused_result))
Returns the upper level node pointer to a R-Tree page. It is assumed
that mtr holds an x-latch on the tree. */
static const rec_t* rtr_get_father_node(
- dict_index_t* index, /*!< in: index */
ulint level, /*!< in: the tree level of search */
const dtuple_t* tuple, /*!< in: data tuple; NOTE: n_fields_cmp in
tuple must be set so that it cannot get
@@ -647,6 +634,7 @@ static const rec_t* rtr_get_father_node(
{
const rec_t* rec = nullptr;
auto had_rtr = btr_cur->rtr_info;
+ dict_index_t* const index = btr_cur->index();
/* Try to optimally locate the parent node. Level should always
less than sea_cur->tree_height unless the root is splitting */
@@ -680,7 +668,7 @@ static const rec_t* rtr_get_father_node(
btr_cur->rtr_info = rtr_create_rtr_info(false, false, btr_cur, index);
- if (btr_cur_search_to_nth_level(index, level, tuple,
+ if (btr_cur_search_to_nth_level(level, tuple,
PAGE_CUR_RTREE_LOCATE,
BTR_CONT_MODIFY_TREE, btr_cur, mtr)
!= DB_SUCCESS) {
@@ -764,7 +752,7 @@ rtr_page_get_father_node_ptr(
sea_cur = NULL;
}
- const rec_t* node_ptr = rtr_get_father_node(index, level + 1, tuple,
+ const rec_t* node_ptr = rtr_get_father_node(level + 1, tuple,
sea_cur, cursor,
page_no, mtr);
if (!node_ptr) {
@@ -792,23 +780,18 @@ rtr_page_get_father_block(
/*======================*/
rec_offs* offsets,/*!< in: work area for the return value */
mem_heap_t* heap, /*!< in: memory heap to use */
- dict_index_t* index, /*!< in: b-tree index */
- buf_block_t* block, /*!< in: child page in the index */
mtr_t* mtr, /*!< in: mtr */
btr_cur_t* sea_cur,/*!< in: search cursor, contains information
about parent nodes in search */
btr_cur_t* cursor) /*!< out: cursor on node pointer record,
its page x-latched */
{
- rec_t* rec = page_rec_get_next(
- page_get_infimum_rec(buf_block_get_frame(block)));
- if (!rec) {
- return nullptr;
- }
- btr_cur_position(index, rec, block, cursor);
-
- return(rtr_page_get_father_node_ptr(offsets, heap, sea_cur,
- cursor, mtr));
+ rec_t *rec=
+ page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame));
+ if (!rec)
+ return nullptr;
+ cursor->page_cur.rec= rec;
+ return rtr_page_get_father_node_ptr(offsets, heap, sea_cur, cursor, mtr);
}
/*******************************************************************//**
@@ -826,7 +809,7 @@ rtr_create_rtr_info(
{
rtr_info_t* rtr_info;
- index = index ? index : cursor->index;
+ index = index ? index : cursor->index();
ut_ad(index);
rtr_info = static_cast<rtr_info_t*>(ut_zalloc_nokey(sizeof(*rtr_info)));
@@ -1163,6 +1146,7 @@ rtr_cur_restore_position(
ut_ad(mtr->is_active());
index = btr_cur_get_index(btr_cur);
+ ut_ad(r_cursor->index() == btr_cur->index());
if (r_cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|| r_cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
@@ -1222,7 +1206,6 @@ rtr_cur_restore_position(
/* Page has changed, for R-Tree, the page cannot be shrunk away,
so we search the page and its right siblings */
- buf_block_t* block;
node_seq_t page_ssn;
const page_t* page;
page_cur_t* page_cursor;
@@ -1242,21 +1225,21 @@ rtr_cur_restore_position(
search_again:
ulint up_match = 0, low_match = 0;
- block = buf_page_get_gen(
+ page_cursor->block = buf_page_get_gen(
page_id_t(index->table->space_id, page_no),
zip_size, RW_X_LATCH, NULL, BUF_GET, mtr);
- if (!block) {
+ if (!page_cursor->block) {
corrupted:
ret = false;
goto func_exit;
}
/* Get the page SSN */
- page = buf_block_get_frame(block);
+ page = buf_block_get_frame(page_cursor->block);
page_ssn = page_get_ssn_id(page);
- if (page_cur_search_with_match(block, index, tuple, PAGE_CUR_LE,
+ if (page_cur_search_with_match(tuple, PAGE_CUR_LE,
&up_match, &low_match, page_cursor,
nullptr)) {
goto corrupted;
@@ -1352,7 +1335,7 @@ rtr_store_parent_path(
/*==================*/
const buf_block_t* block, /*!< in: block of the page */
btr_cur_t* btr_cur,/*!< in/out: persistent cursor */
- ulint latch_mode,
+ btr_latch_mode latch_mode,
/*!< in: latch_mode */
ulint level, /*!< in: index level */
mtr_t* mtr) /*!< in: mtr */
@@ -1411,7 +1394,7 @@ rtr_non_leaf_insert_stack_push(
page_cur_position(rec, block, btr_pcur_get_page_cur(my_cursor));
- (btr_pcur_get_btr_cur(my_cursor))->index = index;
+ btr_pcur_get_page_cur(my_cursor)->index = index;
new_seq = rtr_get_current_ssn_id(index);
rtr_non_leaf_stack_push(path, block->page.id().page_no(),
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index eeff09c0c8d..64f24f9a2d3 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1542,7 +1542,8 @@ static void innodb_drop_database(handlerton*, char *path)
std::vector<pfs_os_file_t> to_close;
mtr_t mtr;
mtr.start();
- err= btr_pcur_open_on_user_rec(sys_index, &tuple, PAGE_CUR_GE,
+ pcur.btr_cur.page_cur.index = sys_index;
+ err= btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
if (err != DB_SUCCESS)
goto err_exit;
@@ -2000,9 +2001,8 @@ static void drop_garbage_tables_after_restore()
ut_d(purge_sys.stop_FTS());
mtr.start();
- if (btr_pcur_open_at_index_side(true, dict_sys.sys_tables->indexes.start,
- BTR_SEARCH_LEAF, &pcur, true, 0, &mtr) !=
- DB_SUCCESS)
+ if (pcur.open_leaf(true, dict_sys.sys_tables->indexes.start, BTR_SEARCH_LEAF,
+ &mtr) != DB_SUCCESS)
goto all_fail;
for (;;)
{
@@ -14997,14 +14997,10 @@ inline int ha_innobase::defragment_table()
}
btr_pcur_t pcur;
- pcur.btr_cur.index = nullptr;
- btr_pcur_init(&pcur);
mtr_t mtr;
mtr.start();
- if (dberr_t err= btr_pcur_open_at_index_side(true, index,
- BTR_SEARCH_LEAF, &pcur,
- true, 0, &mtr))
+ if (dberr_t err= pcur.open_leaf(true, index, BTR_SEARCH_LEAF, &mtr))
{
mtr.commit();
return convert_error_code_to_mysql(err, 0, m_user_thd);
@@ -15018,9 +15014,9 @@ inline int ha_innobase::defragment_table()
btr_pcur_move_to_next(&pcur, &mtr);
btr_pcur_store_position(&pcur, &mtr);
mtr.commit();
- ut_ad(pcur.btr_cur.index == index);
+ ut_ad(pcur.index() == index);
const bool interrupted= btr_defragment_add_index(&pcur, m_user_thd);
- btr_pcur_free(&pcur);
+ ut_free(pcur.old_rec_buf);
if (interrupted)
return ER_QUERY_INTERRUPTED;
}
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index d881a424946..9e01cb6500b 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -2128,8 +2128,7 @@ static bool innobase_table_is_empty(const dict_table_t *table,
bool next_page= false;
mtr.start();
- if (btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF,
- &pcur, true, 0, &mtr) != DB_SUCCESS)
+ if (pcur.open_leaf(true, clust_index, BTR_SEARCH_LEAF, &mtr) != DB_SUCCESS)
{
non_empty:
mtr.commit();
@@ -2159,10 +2158,11 @@ next_page:
&mtr);
if (!block)
goto non_empty;
- btr_leaf_page_release(page_cur_get_block(cur), BTR_SEARCH_LEAF, &mtr);
page_cur_set_before_first(block, cur);
if (UNIV_UNLIKELY(!page_cur_move_to_next(cur)))
goto non_empty;
+ const auto s= mtr.get_savepoint();
+ mtr.rollback_to_savepoint(s - 2, s - 1);
}
rec= page_cur_get_rec(cur);
@@ -6038,8 +6038,7 @@ add_all_virtual:
mtr.start();
index->set_modified(mtr);
btr_pcur_t pcur;
- dberr_t err = btr_pcur_open_at_index_side(true, index, BTR_MODIFY_TREE,
- &pcur, true, 0, &mtr);
+ dberr_t err= pcur.open_leaf(true, index, BTR_MODIFY_TREE, &mtr);
if (err != DB_SUCCESS) {
func_exit:
mtr.commit();
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index 792d8c84bcd..895b68777f3 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -466,9 +466,8 @@ err_exit:
ib::info() << "Dumping the change buffer";
ibuf_mtr_start(&mtr);
btr_pcur_t pcur;
- if (DB_SUCCESS == btr_pcur_open_at_index_side(
- true, ibuf.index, BTR_SEARCH_LEAF, &pcur,
- true, 0, &mtr)) {
+ if (DB_SUCCESS
+ == pcur.open_leaf(true, ibuf.index, BTR_SEARCH_LEAF, &mtr)) {
while (btr_pcur_move_to_next_user_rec(&pcur, &mtr)) {
rec_print_old(stderr, btr_pcur_get_rec(&pcur));
}
@@ -2337,9 +2336,11 @@ work_around:
space_id, page_nos[i], heap);
loop:
btr_pcur_t pcur;
+ pcur.btr_cur.page_cur.index = ibuf.index;
+
ibuf_mtr_start(&mtr);
- if (btr_pcur_open(ibuf.index, tuple, PAGE_CUR_GE,
- BTR_MODIFY_LEAF, &pcur, &mtr)
+ if (btr_pcur_open(tuple, PAGE_CUR_GE,
+ BTR_MODIFY_LEAF, &pcur, 0, &mtr)
!= DB_SUCCESS) {
goto done;
}
@@ -2386,16 +2387,11 @@ done:
#endif
}
-/*********************************************************************//**
-Contracts insert buffer trees by reading pages to the buffer pool.
+/** Contract the change buffer by reading pages to the buffer pool.
@return a lower limit for the combined size in bytes of entries which
-will be merged from ibuf trees to the pages read, 0 if ibuf is
-empty */
-static
-ulint
-ibuf_merge_pages(
-/*=============*/
- ulint* n_pages) /*!< out: number of pages to which merged */
+will be merged from ibuf trees to the pages read
+@retval 0 if ibuf.empty */
+ulint ibuf_contract()
{
mtr_t mtr;
btr_pcur_t pcur;
@@ -2403,15 +2399,13 @@ ibuf_merge_pages(
uint32_t page_nos[IBUF_MAX_N_PAGES_MERGED];
uint32_t space_ids[IBUF_MAX_N_PAGES_MERGED];
- *n_pages = 0;
-
ibuf_mtr_start(&mtr);
/* Open a cursor to a randomly chosen leaf of the tree, at a random
position within the leaf */
pcur.pos_state = BTR_PCUR_IS_POSITIONED;
- pcur.old_stored = false;
- pcur.trx_if_known = NULL;
+ pcur.old_rec = nullptr;
+ pcur.trx_if_known = nullptr;
pcur.search_mode = PAGE_CUR_G;
pcur.latch_mode = BTR_SEARCH_LEAF;
@@ -2437,13 +2431,14 @@ ibuf_merge_pages(
return(0);
}
+ ulint n_pages = 0;
sum_sizes = ibuf_get_merge_page_nos(TRUE,
btr_pcur_get_rec(&pcur), &mtr,
space_ids,
- page_nos, n_pages);
+ page_nos, &n_pages);
ibuf_mtr_commit(&mtr);
- ibuf_read_merge_pages(space_ids, page_nos, *n_pages);
+ ibuf_read_merge_pages(space_ids, page_nos, n_pages);
return(sum_sizes + 1);
}
@@ -2470,8 +2465,9 @@ ibuf_merge_space(
/* Position the cursor on the first matching record. */
- dberr_t err = btr_pcur_open(ibuf.index, tuple, PAGE_CUR_GE,
- BTR_SEARCH_LEAF, &pcur, &mtr);
+ pcur.btr_cur.page_cur.index = ibuf.index;
+ dberr_t err = btr_pcur_open(tuple, PAGE_CUR_GE,
+ BTR_SEARCH_LEAF, &pcur, 0, &mtr);
ut_ad(err != DB_SUCCESS || page_validate(btr_pcur_get_page(&pcur),
ibuf.index));
@@ -2515,73 +2511,6 @@ ibuf_merge_space(
return(n_pages);
}
-/** Contract the change buffer by reading pages to the buffer pool.
-@param[out] n_pages number of pages merged
-@param[in] sync whether the caller waits for
-the issued reads to complete
-@return a lower limit for the combined size in bytes of entries which
-will be merged from ibuf trees to the pages read, 0 if ibuf is
-empty */
-MY_ATTRIBUTE((warn_unused_result))
-static ulint ibuf_merge(ulint* n_pages)
-{
- *n_pages = 0;
-
- /* We perform a dirty read of ibuf.empty, without latching
- the insert buffer root page. We trust this dirty read except
- when a slow shutdown is being executed. During a slow
- shutdown, the insert buffer merge must be completed. */
-
- if (ibuf.empty && srv_shutdown_state <= SRV_SHUTDOWN_INITIATED) {
- return(0);
-#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
- } else if (ibuf_debug) {
- return(0);
-#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
- } else {
- return ibuf_merge_pages(n_pages);
- }
-}
-
-/** Contract the change buffer by reading pages to the buffer pool.
-@return a lower limit for the combined size in bytes of entries which
-will be merged from ibuf trees to the pages read, 0 if ibuf is empty */
-static ulint ibuf_contract()
-{
- ulint n_pages;
- return ibuf_merge_pages(&n_pages);
-}
-
-/** Contract the change buffer by reading pages to the buffer pool.
-@return a lower limit for the combined size in bytes of entries which
-will be merged from ibuf trees to the pages read, 0 if ibuf is
-empty */
-ulint ibuf_merge_all()
-{
-#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
- if (ibuf_debug) {
- return(0);
- }
-#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
-
- ulint sum_bytes = 0;
- ulint n_pages = srv_io_capacity;
-
- for (ulint sum_pages = 0; sum_pages < n_pages; ) {
- log_free_check();
- ulint n_pag2;
- ulint n_bytes = ibuf_merge(&n_pag2);
-
- if (n_bytes == 0) {
- break;
- }
-
- sum_bytes += n_bytes;
- }
-
- return sum_bytes;
-}
-
/*********************************************************************//**
Contract insert buffer trees after insert if they are too big. */
UNIV_INLINE
@@ -2591,13 +2520,7 @@ ibuf_contract_after_insert(
ulint entry_size) /*!< in: size of a record which was inserted
into an ibuf tree */
{
- /* Perform dirty reads of ibuf.size and ibuf.max_size, to
- reduce ibuf_mutex contention. ibuf.max_size remains constant
- after ibuf_init_at_db_start(), but ibuf.size should be
- protected by ibuf_mutex. Given that ibuf.size fits in a
- machine word, this should be OK; at worst we are doing some
- excessive ibuf_contract() or occasionally skipping a
- ibuf_contract(). */
+ /* dirty comparison, to avoid contention on ibuf_mutex */
if (ibuf.size < ibuf.max_size) {
return;
}
@@ -2991,8 +2914,8 @@ ibuf_update_max_tablespace_id(void)
ibuf_mtr_start(&mtr);
- if (btr_pcur_open_at_index_side(false, ibuf.index, BTR_SEARCH_LEAF,
- &pcur, true, 0, &mtr) != DB_SUCCESS) {
+ if (pcur.open_leaf(false, ibuf.index, BTR_SEARCH_LEAF, &mtr)
+ != DB_SUCCESS) {
func_exit:
ibuf_mtr_commit(&mtr);
return;
@@ -3170,7 +3093,7 @@ ibuf_index_page_calc_free_from_bits(ulint physical_size, ulint bits)
/** Buffer an operation in the insert/delete buffer, instead of doing it
directly to the disk page, if this is possible.
-@param[in] mode BTR_MODIFY_PREV or BTR_MODIFY_TREE
+@param[in] mode BTR_MODIFY_PREV or BTR_INSERT_TREE
@param[in] op operation type
@param[in] no_counter TRUE=use 5.0.3 format; FALSE=allow delete
buffering
@@ -3185,7 +3108,7 @@ or clustered
static TRANSACTIONAL_TARGET MY_ATTRIBUTE((warn_unused_result))
dberr_t
ibuf_insert_low(
- ulint mode,
+ btr_latch_mode mode,
ibuf_op_t op,
ibool no_counter,
const dtuple_t* entry,
@@ -3225,16 +3148,17 @@ ibuf_insert_low(
do_merge = FALSE;
- /* Perform dirty reads of ibuf.size and ibuf.max_size, to
- reduce ibuf_mutex contention. Given that ibuf.max_size and
- ibuf.size fit in a machine word, this should be OK; at worst
- we are doing some excessive ibuf_contract() or occasionally
+ /* Perform dirty comparison of ibuf.max_size and ibuf.size to
+ reduce ibuf_mutex contention. This should be OK; at worst we
+ are doing some excessive ibuf_contract() or occasionally
skipping an ibuf_contract(). */
- if (ibuf.max_size == 0) {
+ const ulint max_size = ibuf.max_size;
+
+ if (max_size == 0) {
return(DB_STRONG_FAIL);
}
- if (ibuf.size >= ibuf.max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
+ if (ibuf.size >= max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
/* Insert buffer is now too big, contract it but do not try
to insert */
@@ -3265,7 +3189,7 @@ ibuf_insert_low(
the new entry to it without exceeding the free space limit for the
page. */
- if (BTR_LATCH_MODE_WITHOUT_INTENTION(mode) == BTR_MODIFY_TREE) {
+ if (mode == BTR_INSERT_TREE) {
for (;;) {
mysql_mutex_lock(&ibuf_pessimistic_insert_mutex);
mysql_mutex_lock(&ibuf_mutex);
@@ -3287,18 +3211,16 @@ ibuf_insert_low(
}
ibuf_mtr_start(&mtr);
+ pcur.btr_cur.page_cur.index = ibuf.index;
- err = btr_pcur_open(ibuf.index, ibuf_entry, PAGE_CUR_LE, mode, &pcur,
- &mtr);
+ err = btr_pcur_open(ibuf_entry, PAGE_CUR_LE, mode, &pcur, 0, &mtr);
if (err != DB_SUCCESS) {
func_exit:
ibuf_mtr_commit(&mtr);
ut_free(pcur.old_rec_buf);
mem_heap_free(heap);
- if (err == DB_SUCCESS
- && BTR_LATCH_MODE_WITHOUT_INTENTION(mode)
- == BTR_MODIFY_TREE) {
+ if (err == DB_SUCCESS && mode == BTR_INSERT_TREE) {
ibuf_contract_after_insert(entry_size);
}
@@ -3345,7 +3267,7 @@ func_exit:
until after the IBUF_OP_DELETE has been buffered. */
fail_exit:
- if (BTR_LATCH_MODE_WITHOUT_INTENTION(mode) == BTR_MODIFY_TREE) {
+ if (mode == BTR_INSERT_TREE) {
mysql_mutex_unlock(&ibuf_mutex);
mysql_mutex_unlock(&ibuf_pessimistic_insert_mutex);
}
@@ -3461,8 +3383,7 @@ commit_exit:
ibuf.empty = page_is_empty(root);
}
} else {
- ut_ad(BTR_LATCH_MODE_WITHOUT_INTENTION(mode)
- == BTR_MODIFY_TREE);
+ ut_ad(mode == BTR_INSERT_TREE);
/* We acquire an sx-latch to the root page before the insert,
because a pessimistic insert releases the tree x-latch,
@@ -3637,7 +3558,7 @@ skip_watch:
entry, entry_size,
index, page_id, zip_size, thr);
if (err == DB_FAIL) {
- err = ibuf_insert_low(BTR_MODIFY_TREE | BTR_LATCH_FOR_INSERT,
+ err = ibuf_insert_low(BTR_INSERT_TREE,
op, no_counter, entry, entry_size,
index, page_id, zip_size, thr);
}
@@ -3658,30 +3579,27 @@ dberr_t
ibuf_insert_to_index_page_low(
/*==========================*/
const dtuple_t* entry, /*!< in: buffered entry to insert */
- buf_block_t* block, /*!< in/out: index page where the buffered
- entry should be placed */
- dict_index_t* index, /*!< in: record descriptor */
rec_offs** offsets,/*!< out: offsets on *rec */
mem_heap_t* heap, /*!< in/out: memory heap */
mtr_t* mtr, /*!< in/out: mtr */
page_cur_t* page_cur)/*!< in/out: cursor positioned on the record
after which to insert the buffered entry */
{
- if (page_cur_tuple_insert(page_cur, entry, index, offsets, &heap, 0, mtr))
+ if (page_cur_tuple_insert(page_cur, entry, offsets, &heap, 0, mtr))
return DB_SUCCESS;
/* Page reorganization or recompression should already have been
attempted by page_cur_tuple_insert(). Besides, per
ibuf_index_page_calc_free_zip() the page should not have been
recompressed or reorganized. */
- ut_ad(!is_buf_block_get_page_zip(block));
+ ut_ad(!is_buf_block_get_page_zip(page_cur->block));
/* If the record did not fit, reorganize */
- if (dberr_t err= btr_page_reorganize(page_cur, index, mtr))
+ if (dberr_t err= btr_page_reorganize(page_cur, mtr))
return err;
/* This time the record must fit */
- if (page_cur_tuple_insert(page_cur, entry, index, offsets, &heap, 0, mtr))
+ if (page_cur_tuple_insert(page_cur, entry, offsets, &heap, 0, mtr))
return DB_SUCCESS;
return DB_CORRUPTION;
@@ -3738,8 +3656,10 @@ ibuf_insert_to_index_page(
}
ulint up_match = 0, low_match = 0;
+ page_cur.index = index;
+ page_cur.block = block;
- if (page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
+ if (page_cur_search_with_match(entry, PAGE_CUR_LE,
&up_match, &low_match, &page_cur,
nullptr)) {
return DB_CORRUPTION;
@@ -3786,7 +3706,7 @@ ibuf_insert_to_index_page(
if (!row_upd_changes_field_size_or_external(index, offsets,
update)
&& (!page_zip || btr_cur_update_alloc_zip(
- page_zip, &page_cur, index, offsets,
+ page_zip, &page_cur, offsets,
rec_offs_size(offsets), false, mtr))) {
/* This is the easy case. Do something similar
to btr_cur_update_in_place(). */
@@ -3827,7 +3747,7 @@ ibuf_insert_to_index_page(
/* Delete the different-length record, and insert the
buffered one. */
- page_cur_delete_rec(&page_cur, index, offsets, mtr);
+ page_cur_delete_rec(&page_cur, offsets, mtr);
if (!(page_cur_move_to_prev(&page_cur))) {
err = DB_CORRUPTION;
goto updated_in_place;
@@ -3836,8 +3756,8 @@ ibuf_insert_to_index_page(
offsets = NULL;
}
- err = ibuf_insert_to_index_page_low(entry, block, index,
- &offsets, heap, mtr, &page_cur);
+ err = ibuf_insert_to_index_page_low(entry, &offsets, heap, mtr,
+ &page_cur);
updated_in_place:
mem_heap_free(heap);
@@ -3853,16 +3773,18 @@ ibuf_set_del_mark(
/*==============*/
const dtuple_t* entry, /*!< in: entry */
buf_block_t* block, /*!< in/out: block */
- const dict_index_t* index, /*!< in: record descriptor */
+ dict_index_t* index, /*!< in: record descriptor */
mtr_t* mtr) /*!< in: mtr */
{
page_cur_t page_cur;
+ page_cur.block = block;
+ page_cur.index = index;
ulint up_match = 0, low_match = 0;
ut_ad(ibuf_inside(mtr));
ut_ad(dtuple_check_typed(entry));
- if (!page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
+ if (!page_cur_search_with_match(entry, PAGE_CUR_LE,
&up_match, &low_match, &page_cur,
nullptr)
&& low_match == dtuple_get_n_fields(entry)) {
@@ -3914,6 +3836,8 @@ ibuf_delete(
before latching any further pages */
{
page_cur_t page_cur;
+ page_cur.block = block;
+ page_cur.index = index;
ulint up_match = 0, low_match = 0;
ut_ad(ibuf_inside(mtr));
@@ -3921,7 +3845,7 @@ ibuf_delete(
ut_ad(!index->is_spatial());
ut_ad(!index->is_clust());
- if (!page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
+ if (!page_cur_search_with_match(entry, PAGE_CUR_LE,
&up_match, &low_match, &page_cur,
nullptr)
&& low_match == dtuple_get_n_fields(entry)) {
@@ -3974,7 +3898,7 @@ ibuf_delete(
#ifdef UNIV_ZIP_DEBUG
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
- page_cur_delete_rec(&page_cur, index, offsets, mtr);
+ page_cur_delete_rec(&page_cur, offsets, mtr);
#ifdef UNIV_ZIP_DEBUG
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
@@ -4001,13 +3925,12 @@ ibuf_restore_pos(
const page_id_t page_id,/*!< in: page identifier */
const dtuple_t* search_tuple,
/*!< in: search tuple for entries of page_no */
- ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_PURGE_TREE */
btr_pcur_t* pcur, /*!< in/out: persistent cursor whose
position is to be restored */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
- ut_ad(mode == BTR_MODIFY_LEAF
- || BTR_LATCH_MODE_WITHOUT_INTENTION(mode) == BTR_MODIFY_TREE);
+ ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_PURGE_TREE);
if (UNIV_LIKELY(pcur->restore_position(mode, mtr) ==
btr_pcur_t::SAME_ALL)) {
@@ -4090,8 +4013,7 @@ bool ibuf_delete_rec(const page_id_t page_id, btr_pcur_t* pcur,
ibuf_mtr_start(mtr);
mysql_mutex_lock(&ibuf_mutex);
- if (!ibuf_restore_pos(page_id, search_tuple,
- BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
+ if (!ibuf_restore_pos(page_id, search_tuple, BTR_PURGE_TREE,
pcur, mtr)) {
mysql_mutex_unlock(&ibuf_mutex);
@@ -4278,13 +4200,14 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block,
memset(mops, 0, sizeof(mops));
memset(dops, 0, sizeof(dops));
+ pcur.btr_cur.page_cur.index = ibuf.index;
loop:
ibuf_mtr_start(&mtr);
/* Position pcur in the insert buffer at the first entry for this
index page */
- if (btr_pcur_open_on_user_rec(ibuf.index, search_tuple, PAGE_CUR_GE,
+ if (btr_pcur_open_on_user_rec(search_tuple, PAGE_CUR_GE,
BTR_MODIFY_LEAF, &pcur, &mtr)
!= DB_SUCCESS) {
err = DB_CORRUPTION;
@@ -4437,7 +4360,6 @@ loop:
goto loop;
} else if (btr_pcur_is_after_last_on_page(&pcur)) {
ibuf_mtr_commit(&mtr);
- ut_free(pcur.old_rec_buf);
goto loop;
}
}
@@ -4485,13 +4407,15 @@ void ibuf_delete_for_discarded_space(uint32_t space)
search_tuple = ibuf_search_tuple_build(space, 0, heap);
memset(dops, 0, sizeof(dops));
+ pcur.btr_cur.page_cur.index = ibuf.index;
+
loop:
log_free_check();
ibuf_mtr_start(&mtr);
/* Position pcur in the insert buffer at the first entry for the
space */
- if (btr_pcur_open_on_user_rec(ibuf.index, search_tuple, PAGE_CUR_GE,
+ if (btr_pcur_open_on_user_rec(search_tuple, PAGE_CUR_GE,
BTR_MODIFY_LEAF, &pcur, &mtr)
!= DB_SUCCESS) {
goto leave_loop;
@@ -4577,7 +4501,7 @@ ibuf_print(
fprintf(file,
"Ibuf: size " ULINTPF ", free list len " ULINTPF ","
" seg size " ULINTPF ", " ULINTPF " merges\n",
- ibuf.size,
+ ulint{ibuf.size},
ibuf.free_list_len,
ibuf.seg_size,
ulint{ibuf.n_merges});
diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h
index a4bf42adcfb..a2aa46b62da 100644
--- a/storage/innobase/include/btr0btr.h
+++ b/storage/innobase/include/btr0btr.h
@@ -55,103 +55,8 @@ not acceptable for it to lead to mysterious memory corruption, but it
is acceptable for the program to die with a clear assert failure. */
#define BTR_MAX_LEVELS 100
-/** Latching modes for btr_cur_search_to_nth_level(). */
-enum btr_latch_mode {
- /** Search a record on a leaf page and S-latch it. */
- BTR_SEARCH_LEAF = RW_S_LATCH,
- /** (Prepare to) modify a record on a leaf page and X-latch it. */
- BTR_MODIFY_LEAF = RW_X_LATCH,
- /** Obtain no latches. */
- BTR_NO_LATCHES = RW_NO_LATCH,
- /** Search the previous record. */
- BTR_SEARCH_PREV = 4 | BTR_SEARCH_LEAF,
- /** Modify the previous record. */
- BTR_MODIFY_PREV = 4 | BTR_MODIFY_LEAF,
- /** Start searching the entire B-tree. */
- BTR_SEARCH_TREE = 8 | BTR_SEARCH_LEAF,
- /** Start modifying1 the entire B-tree. */
- BTR_MODIFY_TREE = 8 | BTR_MODIFY_LEAF,
- /** Continue searching the entire B-tree. */
- BTR_CONT_SEARCH_TREE = 4 | BTR_SEARCH_TREE,
- /** Continue modifying the entire B-tree. */
- BTR_CONT_MODIFY_TREE = 4 | BTR_MODIFY_TREE,
-
- /* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually
- exclusive. */
- /** The search tuple will be inserted to the secondary index
- at the searched position. When the leaf page is not in the
- buffer pool, try to use the change buffer. */
- BTR_INSERT = 64,
-
- /** Try to delete mark a secondary index leaf page record at
- the searched position using the change buffer when the page is
- not in the buffer pool. */
- BTR_DELETE_MARK = 128,
-
- /** Try to purge the record using the change buffer when the
- secondary index leaf page is not in the buffer pool. */
- BTR_DELETE = BTR_INSERT | BTR_DELETE_MARK,
-
- /** The caller is already holding dict_index_t::lock S-latch. */
- BTR_ALREADY_S_LATCHED = 256,
- /** Search and S-latch a leaf page, assuming that the
- dict_index_t::lock S-latch is being held. */
- BTR_SEARCH_LEAF_ALREADY_S_LATCHED = BTR_SEARCH_LEAF
- | BTR_ALREADY_S_LATCHED,
- /** Search the entire index tree, assuming that the
- dict_index_t::lock S-latch is being held. */
- BTR_SEARCH_TREE_ALREADY_S_LATCHED = BTR_SEARCH_TREE
- | BTR_ALREADY_S_LATCHED,
- /** Search and X-latch a leaf page, assuming that the
- dict_index_t::lock S-latch is being held. */
- BTR_MODIFY_LEAF_ALREADY_S_LATCHED = BTR_MODIFY_LEAF
- | BTR_ALREADY_S_LATCHED,
-
- /** Attempt to delete-mark a secondary index record. */
- BTR_DELETE_MARK_LEAF = BTR_MODIFY_LEAF | BTR_DELETE_MARK,
- /** Attempt to delete-mark a secondary index record
- while holding the dict_index_t::lock S-latch. */
- BTR_DELETE_MARK_LEAF_ALREADY_S_LATCHED = BTR_DELETE_MARK_LEAF
- | BTR_ALREADY_S_LATCHED,
- /** Attempt to purge a secondary index record. */
- BTR_PURGE_LEAF = BTR_MODIFY_LEAF | BTR_DELETE,
- /** Attempt to purge a secondary index record
- while holding the dict_index_t::lock S-latch. */
- BTR_PURGE_LEAF_ALREADY_S_LATCHED = BTR_PURGE_LEAF
- | BTR_ALREADY_S_LATCHED,
-
- /** In the case of BTR_MODIFY_TREE, the caller specifies
- the intention to delete record only. It is used to optimize
- block->lock range.*/
- BTR_LATCH_FOR_DELETE = 512,
-
- /** Attempt to purge a secondary index record in the tree. */
- BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE
-};
-
-/** This flag ORed to BTR_INSERT says that we can ignore possible
-UNIQUE definition on secondary indexes when we decide if we can use
-the insert buffer to speed up inserts */
-#define BTR_IGNORE_SEC_UNIQUE 2048U
-
-/** In the case of BTR_MODIFY_TREE, the caller specifies the intention
-to insert record only. It is used to optimize block->lock range.*/
-#define BTR_LATCH_FOR_INSERT 4096U
-
-/** This flag is for undo insert of rtree. For rtree, we need this flag
-to find proper rec to undo insert.*/
-#define BTR_RTREE_UNDO_INS 8192U
-
-/** In the case of BTR_MODIFY_LEAF, the caller intends to allocate or
-free the pages of externally stored fields. */
-#define BTR_MODIFY_EXTERNAL 16384U
-
-/** Try to delete mark the record at the searched position when the
-record is in spatial index */
-#define BTR_RTREE_DELETE_MARK 32768U
-
#define BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode) \
- ((latch_mode) & ulint(~(BTR_INSERT \
+ btr_latch_mode((latch_mode) & ~(BTR_INSERT \
| BTR_DELETE_MARK \
| BTR_RTREE_UNDO_INS \
| BTR_RTREE_DELETE_MARK \
@@ -159,13 +64,11 @@ record is in spatial index */
| BTR_IGNORE_SEC_UNIQUE \
| BTR_ALREADY_S_LATCHED \
| BTR_LATCH_FOR_INSERT \
- | BTR_LATCH_FOR_DELETE \
- | BTR_MODIFY_EXTERNAL)))
+ | BTR_LATCH_FOR_DELETE))
-#define BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode) \
- ((latch_mode) & ulint(~(BTR_LATCH_FOR_INSERT \
- | BTR_LATCH_FOR_DELETE \
- | BTR_MODIFY_EXTERNAL)))
+#define BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode) \
+ btr_latch_mode((latch_mode) \
+ & ~(BTR_LATCH_FOR_INSERT | BTR_LATCH_FOR_DELETE))
/**************************************************************//**
Checks and adjusts the root node of a tree during IMPORT TABLESPACE.
@@ -229,17 +132,6 @@ inline uint32_t btr_page_get_prev(const page_t* page)
}
/**************************************************************//**
-Releases the latch on a leaf page and bufferunfixes it. */
-UNIV_INLINE
-void
-btr_leaf_page_release(
-/*==================*/
- buf_block_t* block, /*!< in: buffer block */
- ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or
- BTR_MODIFY_LEAF */
- mtr_t* mtr) /*!< in: mtr */
- MY_ATTRIBUTE((nonnull));
-/**************************************************************//**
Gets the child node file address in a node pointer.
NOTE: the offsets array must contain all offsets for the record since
we read the last field according to offsets and assume that it contains
@@ -359,15 +251,12 @@ be done either within the same mini-transaction, or by invoking
ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
IBUF_BITMAP_FREE is unaffected by reorganization.
+@param cursor page cursor
+@param mtr mini-transaction
@return error code
@retval DB_FAIL if reorganizing a ROW_FORMAT=COMPRESSED page failed */
-dberr_t
-btr_page_reorganize(
-/*================*/
- page_cur_t* cursor, /*!< in/out: page cursor */
- dict_index_t* index, /*!< in: the index tree of the page */
- mtr_t* mtr) /*!< in/out: mini-transaction */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+dberr_t btr_page_reorganize(page_cur_t *cursor, mtr_t *mtr)
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Decide if the page should be split at the convergence point of inserts
converging to the left.
@param[in] cursor insert position
@@ -445,13 +334,10 @@ inline void btr_set_min_rec_mark(rec_t *rec, const buf_block_t &block,
}
/** Seek to the parent page of a B-tree page.
-@param[in,out] index b-tree
-@param[in] block child page
@param[in,out] mtr mini-transaction
-@param[out] cursor cursor pointing to the x-latched parent page
+@param[in,out] cursor cursor pointing to the x-latched parent page
@return whether the cursor was successfully positioned */
-bool btr_page_get_father(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
- btr_cur_t* cursor)
+bool btr_page_get_father(mtr_t* mtr, btr_cur_t* cursor)
MY_ATTRIBUTE((nonnull,warn_unused_result));
#ifdef UNIV_DEBUG
/************************************************************//**
diff --git a/storage/innobase/include/btr0btr.inl b/storage/innobase/include/btr0btr.inl
index f92622cc400..9a9e39b6b4c 100644
--- a/storage/innobase/include/btr0btr.inl
+++ b/storage/innobase/include/btr0btr.inl
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, 2021, MariaDB Corporation.
+Copyright (c) 2015, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -24,10 +24,7 @@ The B-tree
Created 6/2/1994 Heikki Tuuri
*******************************************************/
-#include "mach0data.h"
-#include "mtr0mtr.h"
#include "mtr0log.h"
-#include "page0zip.h"
/**************************************************************//**
Gets the index id field of a page.
@@ -112,38 +109,3 @@ btr_node_ptr_get_child_page_no(
return(page_no);
}
-
-/**************************************************************//**
-Releases the latches on a leaf page and bufferunfixes it. */
-UNIV_INLINE
-void
-btr_leaf_page_release(
-/*==================*/
- buf_block_t* block, /*!< in: buffer block */
- ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or
- BTR_MODIFY_LEAF */
- mtr_t* mtr) /*!< in: mtr */
-{
- ut_ad(latch_mode == BTR_SEARCH_LEAF
- || latch_mode == BTR_MODIFY_LEAF
- || latch_mode == BTR_NO_LATCHES);
-
- ut_ad(!mtr->memo_contains_flagged(block, MTR_MEMO_MODIFY));
-
- mtr_memo_type_t mode;
- switch (latch_mode) {
- case BTR_SEARCH_LEAF:
- mode = MTR_MEMO_PAGE_S_FIX;
- break;
- case BTR_MODIFY_LEAF:
- mode = MTR_MEMO_PAGE_X_FIX;
- break;
- case BTR_NO_LATCHES:
- mode = MTR_MEMO_BUF_FIX;
- break;
- default:
- ut_a(0);
- }
-
- mtr->memo_release(block, mode);
-}
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index 6626b2e948a..aa890be9936 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -96,7 +96,7 @@ btr_cur_get_page(
Returns the index of a cursor.
@param cursor b-tree cursor
@return index */
-#define btr_cur_get_index(cursor) ((cursor)->index)
+#define btr_cur_get_index(cursor) ((cursor)->index())
/*********************************************************//**
Positions a tree cursor at a given record. */
UNIV_INLINE
@@ -137,7 +137,7 @@ bool
btr_cur_optimistic_latch_leaves(
buf_block_t* block,
ib_uint64_t modify_clock,
- ulint* latch_mode,
+ btr_latch_mode* latch_mode,
btr_cur_t* cursor,
mtr_t* mtr);
@@ -148,7 +148,6 @@ to node pointer page number fields on the upper levels of the tree!
Note that if mode is PAGE_CUR_LE, which is used in inserts, then
cursor->up_match and cursor->low_match both will have sensible values.
If mode is PAGE_CUR_GE, then up_match will a have a sensible value.
-@param index index
@param level the tree level of search
@param tuple data tuple; NOTE: n_fields_cmp in tuple must be set so that
it cannot get compared to the node ptr page number field!
@@ -166,27 +165,13 @@ If mode is PAGE_CUR_GE, then up_match will a have a sensible value.
@param mtr mini-transaction
@param autoinc PAGE_ROOT_AUTO_INC to be written (0 if none)
@return DB_SUCCESS on success or error code otherwise */
-dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level,
+dberr_t btr_cur_search_to_nth_level(ulint level,
const dtuple_t *tuple,
- page_cur_mode_t mode, ulint latch_mode,
+ page_cur_mode_t mode,
+ btr_latch_mode latch_mode,
btr_cur_t *cursor, mtr_t *mtr,
ib_uint64_t autoinc= 0);
-/*****************************************************************//**
-Opens a cursor at either end of an index.
-@return DB_SUCCESS or error code */
-dberr_t
-btr_cur_open_at_index_side(
- bool from_left, /*!< in: true if open to the low end,
- false if to the high end */
- dict_index_t* index, /*!< in: index */
- ulint latch_mode, /*!< in: latch mode */
- btr_cur_t* cursor, /*!< in/out: cursor */
- ulint level, /*!< in: level to search for
- (0=leaf) */
- mtr_t* mtr) /*!< in/out: mini-transaction */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
/**********************************************************************//**
Positions a cursor at a randomly chosen position within a B-tree.
@return true if the index is available and we have put the cursor, false
@@ -194,7 +179,7 @@ if the index is unavailable */
bool
btr_cur_open_at_rnd_pos(
dict_index_t* index, /*!< in: index */
- ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
+ btr_latch_mode latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
btr_cur_t* cursor, /*!< in/out: B-tree cursor */
mtr_t* mtr) /*!< in: mtr */
MY_ATTRIBUTE((nonnull,warn_unused_result));
@@ -281,7 +266,6 @@ btr_cur_update_alloc_zip_func(
/*==========================*/
page_zip_des_t* page_zip,/*!< in/out: compressed page */
page_cur_t* cursor, /*!< in/out: B-tree page cursor */
- dict_index_t* index, /*!< in: the index corresponding to cursor */
#ifdef UNIV_DEBUG
rec_offs* offsets,/*!< in/out: offsets of the cursor record */
#endif /* UNIV_DEBUG */
@@ -291,11 +275,11 @@ btr_cur_update_alloc_zip_func(
mtr_t* mtr) /*!< in/out: mini-transaction */
MY_ATTRIBUTE((nonnull, warn_unused_result));
#ifdef UNIV_DEBUG
-# define btr_cur_update_alloc_zip(page_zip,cursor,index,offsets,len,cr,mtr) \
- btr_cur_update_alloc_zip_func(page_zip,cursor,index,offsets,len,cr,mtr)
+# define btr_cur_update_alloc_zip(page_zip,cursor,offsets,len,cr,mtr) \
+ btr_cur_update_alloc_zip_func(page_zip,cursor,offsets,len,cr,mtr)
#else /* UNIV_DEBUG */
-# define btr_cur_update_alloc_zip(page_zip,cursor,index,offsets,len,cr,mtr) \
- btr_cur_update_alloc_zip_func(page_zip,cursor,index,len,cr,mtr)
+# define btr_cur_update_alloc_zip(page_zip,cursor,offsets,len,cr,mtr) \
+ btr_cur_update_alloc_zip_func(page_zip,cursor,len,cr,mtr)
#endif /* UNIV_DEBUG */
/** Apply an update vector to a record. No field size changes are allowed.
@@ -689,7 +673,7 @@ btr_rec_copy_externally_stored_field(
void
btr_cur_latch_leaves(
buf_block_t* block,
- ulint latch_mode,
+ btr_latch_mode latch_mode,
btr_cur_t* cursor,
mtr_t* mtr,
btr_latch_leaves_t* latch_leaves = nullptr);
@@ -752,7 +736,6 @@ enum btr_cur_method {
/** The tree cursor: the definition appears here only for the compiler
to know struct size! */
struct btr_cur_t {
- dict_index_t* index; /*!< index where positioned */
page_cur_t page_cur; /*!< page cursor */
purge_node_t* purge_node; /*!< purge node, for BTR_DELETE */
buf_block_t* left_block; /*!< this field is used to store
@@ -817,28 +800,19 @@ struct btr_cur_t {
information of the path through
the tree */
rtr_info_t* rtr_info; /*!< rtree search info */
- btr_cur_t():thr(NULL), rtr_info(NULL) {}
- /* default values */
- /** Zero-initialize all fields */
- void init()
- {
- index = NULL;
- memset(&page_cur, 0, sizeof page_cur);
- purge_node = NULL;
- left_block = NULL;
- thr = NULL;
- flag = btr_cur_method(0);
- tree_height = 0;
- up_match = 0;
- up_bytes = 0;
- low_match = 0;
- low_bytes = 0;
- n_fields = 0;
- n_bytes = 0;
- fold = 0;
- path_arr = NULL;
- rtr_info = NULL;
- }
+ btr_cur_t() { memset((void*) this, 0, sizeof *this); }
+
+ dict_index_t *index() const { return page_cur.index; }
+ buf_block_t *block() const { return page_cur.block; }
+
+ /** Open the cursor on the first or last record.
+ @param first true=first record, false=last record
+ @param index B-tree
+ @param latch_mode which latches to acquire
+ @param mtr mini-transaction
+ @return error code */
+ dberr_t open_leaf(bool first, dict_index_t *index, btr_latch_mode latch_mode,
+ mtr_t *mtr);
};
/** Modify the delete-mark flag of a record.
diff --git a/storage/innobase/include/btr0cur.inl b/storage/innobase/include/btr0cur.inl
index 76a2d3be49c..955cf34288e 100644
--- a/storage/innobase/include/btr0cur.inl
+++ b/storage/innobase/include/btr0cur.inl
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2018, 2021, MariaDB Corporation.
+Copyright (c) 2018, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -72,7 +72,7 @@ btr_cur_position(
btr_cur_t* cursor) /*!< out: cursor */
{
page_cur_position(rec, block, btr_cur_get_page_cur(cursor));
- cursor->index = index;
+ cursor->page_cur.index = index;
}
/*********************************************************************//**
@@ -98,14 +98,14 @@ btr_cur_compress_recommendation(
if (!page_has_siblings(page)
|| page_get_data_size(page)
- < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)) {
+ < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index())) {
/* The page fillfactor has dropped below a predefined
minimum value OR the level in the B-tree contains just
one page: we recommend compression if this is not the
root page. */
- return cursor->index->page
+ return cursor->index()->page
!= btr_cur_get_block(cursor)->page.id().page_no();
}
@@ -133,14 +133,14 @@ btr_cur_can_delete_without_compress(
if (!page_has_siblings(page) || page_get_n_recs(page) < 2
|| page_get_data_size(page) - rec_size
- < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)) {
+ < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index())) {
/* The page fillfactor will drop below a predefined
minimum value, OR the level in the B-tree contains just
one page, OR the page will become empty: we recommend
compression if this is not the root page. */
- return cursor->index->page
+ return cursor->index()->page
== btr_cur_get_block(cursor)->page.id().page_no();
}
diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h
index 5103484da29..cd8eacdc212 100644
--- a/storage/innobase/include/btr0pcur.h
+++ b/storage/innobase/include/btr0pcur.h
@@ -46,13 +46,6 @@ of a scroll cursor easier */
};
/**************************************************************//**
-Allocates memory for a persistent cursor object and initializes the cursor.
-@return own: persistent cursor */
-btr_pcur_t*
-btr_pcur_create_for_mysql(void);
-/*============================*/
-
-/**************************************************************//**
Resets a persistent cursor object, freeing ::old_rec_buf if it is
allocated and resetting the other members to their initial values. */
void
@@ -61,12 +54,6 @@ btr_pcur_reset(
btr_pcur_t* cursor);/*!< in, out: persistent cursor */
/**************************************************************//**
-Frees the memory for a persistent cursor object. */
-void
-btr_pcur_free_for_mysql(
-/*====================*/
- btr_pcur_t* cursor); /*!< in, own: persistent cursor */
-/**************************************************************//**
Copies the stored position of a pcur to another pcur. */
void
btr_pcur_copy_stored_position(
@@ -83,21 +70,11 @@ btr_pcur_init(
/*==========*/
btr_pcur_t* pcur); /*!< in: persistent cursor */
-/** Free old_rec_buf.
-@param[in] pcur Persistent cursor holding old_rec to be freed. */
-UNIV_INLINE
-void
-btr_pcur_free(
- btr_pcur_t* pcur);
-
/**************************************************************//**
Initializes and opens a persistent cursor to an index tree. */
inline
dberr_t
-btr_pcur_open_low(
-/*==============*/
- dict_index_t* index, /*!< in: index */
- ulint level, /*!< in: level in the btree */
+btr_pcur_open(
const dtuple_t* tuple, /*!< in: tuple on which search done */
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...;
NOTE that if the search is made using a unique
@@ -105,17 +82,14 @@ btr_pcur_open_low(
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
may end up on the previous page from the
record! */
- ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
+ btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
mtr_t* mtr) /*!< in: mtr */
MY_ATTRIBUTE((nonnull, warn_unused_result));
-#define btr_pcur_open(i,t,md,l,c,m) \
- btr_pcur_open_low(i,0,t,md,l,c,0,m)
/** Opens an persistent cursor to an index tree without initializing the
cursor.
-@param index index
@param tuple tuple on which search done
@param mode PAGE_CUR_L, ...; NOTE that if the search is made using a
unique prefix of a record, mode should be PAGE_CUR_LE, not
@@ -126,26 +100,11 @@ cursor.
@param mtr mini-transaction
@return DB_SUCCESS on success or error code otherwise. */
inline
-dberr_t btr_pcur_open_with_no_init(dict_index_t *index, const dtuple_t *tuple,
- page_cur_mode_t mode, ulint latch_mode,
+dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple,
+ page_cur_mode_t mode,
+ btr_latch_mode latch_mode,
btr_pcur_t *cursor, mtr_t *mtr);
-/*****************************************************************//**
-Opens a persistent cursor at either end of an index. */
-UNIV_INLINE
-dberr_t
-btr_pcur_open_at_index_side(
-/*========================*/
- bool from_left, /*!< in: true if open to the low end,
- false if to the high end */
- dict_index_t* index, /*!< in: index */
- ulint latch_mode, /*!< in: latch mode */
- btr_pcur_t* pcur, /*!< in/out: cursor */
- bool init_pcur, /*!< in: whether to initialize pcur */
- ulint level, /*!< in: level to search for
- (0=leaf) */
- mtr_t* mtr) /*!< in/out: mini-transaction */
- MY_ATTRIBUTE((nonnull,warn_unused_result));
/**************************************************************//**
Gets the up_match value for a pcur after a search.
@return number of matched fields at the cursor or to the right if
@@ -356,102 +315,103 @@ enum pcur_pos_t {
/* The persistent B-tree cursor structure. This is used mainly for SQL
selects, updates, and deletes. */
-struct btr_pcur_t{
- /** Return value of restore_position() */
- enum restore_status {
- /** cursor position on user rec and points on the record with
- the same field values as in the stored record */
- SAME_ALL,
- /** cursor position is on user rec and points on the record with
- the same unique field values as in the stored record */
- SAME_UNIQ,
- /** cursor position is not on user rec or points on the record
- with not the same uniq field values as in the stored record */
- NOT_SAME,
- /** the index tree is corrupted */
- CORRUPTED
- };
- /** a B-tree cursor */
- btr_cur_t btr_cur;
- /** see TODO note below!
- BTR_SEARCH_LEAF, BTR_MODIFY_LEAF, BTR_MODIFY_TREE or BTR_NO_LATCHES,
- depending on the latching state of the page and tree where the cursor
- is positioned; BTR_NO_LATCHES means that the cursor is not currently
- positioned:
- we say then that the cursor is detached; it can be restored to
- attached if the old position was stored in old_rec */
- ulint latch_mode;
- /** true if old_rec is stored */
- bool old_stored;
- /** if cursor position is stored, contains an initial segment of the
- latest record cursor was positioned either on, before or after */
- rec_t* old_rec;
- /** btr_cur.index->n_core_fields when old_rec was copied */
- uint16 old_n_core_fields;
- /** number of fields in old_rec */
- uint16 old_n_fields;
- /** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on
- whether cursor was on, before, or after the old_rec record */
- enum btr_pcur_pos_t rel_pos;
- /** buffer block when the position was stored */
- buf::Block_hint block_when_stored;
- /** the modify clock value of the buffer block when the cursor position
- was stored */
- ib_uint64_t modify_clock;
- /** btr_pcur_store_position() and btr_pcur_restore_position() state. */
- enum pcur_pos_t pos_state;
- /** PAGE_CUR_G, ... */
- page_cur_mode_t search_mode;
- /** the transaction, if we know it; otherwise this field is not defined;
- can ONLY BE USED in error prints in fatal assertion failures! */
- trx_t* trx_if_known;
- /*-----------------------------*/
- /* NOTE that the following fields may possess dynamically allocated
- memory which should be freed if not needed anymore! */
-
- /** NULL, or a dynamically allocated buffer for old_rec */
- byte* old_rec_buf;
- /** old_rec_buf size if old_rec_buf is not NULL */
- ulint buf_size;
-
- btr_pcur_t() :
- btr_cur(), latch_mode(RW_NO_LATCH),
- old_stored(false), old_rec(NULL),
- old_n_fields(0), rel_pos(btr_pcur_pos_t(0)),
- block_when_stored(),
- modify_clock(0), pos_state(BTR_PCUR_NOT_POSITIONED),
- search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL),
- old_rec_buf(NULL), buf_size(0)
- {
- btr_cur.init();
- }
-
- /** Return the index of this persistent cursor */
- dict_index_t* index() const { return(btr_cur.index); }
- MY_ATTRIBUTE((nonnull, warn_unused_result))
- /** Restores the stored position of a persistent cursor bufferfixing
- the page and obtaining the specified latches. If the cursor position
- was saved when the
- (1) cursor was positioned on a user record: this function restores the
- position to the last record LESS OR EQUAL to the stored record;
- (2) cursor was positioned on a page infimum record: restores the
- position to the last record LESS than the user record which was the
- successor of the page infimum;
- (3) cursor was positioned on the page supremum: restores to the first
- record GREATER than the user record which was the predecessor of the
- supremum.
- (4) cursor was positioned before the first or after the last in an
- empty tree: restores to before first or after the last in the tree.
- @param restore_latch_mode BTR_SEARCH_LEAF, ...
- @param mtr mtr
- @retval SAME_ALL cursor position on user rec and points on
- the record with the same field values as in the stored record,
- @retval SAME_UNIQ cursor position is on user rec and points on the
- record with the same unique field values as in the stored record,
- @retval NOT_SAME cursor position is not on user rec or points on
- the record with not the same uniq field values as in the stored
- @retval CORRUPTED if the index is corrupted */
- restore_status restore_position(ulint latch_mode, mtr_t *mtr);
+struct btr_pcur_t
+{
+ /** Return value of restore_position() */
+ enum restore_status {
+ /** cursor position on user rec and points on the record with
+ the same field values as in the stored record */
+ SAME_ALL,
+ /** cursor position is on user rec and points on the record with
+ the same unique field values as in the stored record */
+ SAME_UNIQ,
+ /** cursor position is not on user rec or points on the record
+ with not the same uniq field values as in the stored record */
+ NOT_SAME,
+ /** the index tree is corrupted */
+ CORRUPTED
+ };
+ /** a B-tree cursor */
+ btr_cur_t btr_cur;
+ /** @see BTR_PCUR_WAS_POSITIONED
+ BTR_SEARCH_LEAF, BTR_MODIFY_LEAF, BTR_MODIFY_TREE or BTR_NO_LATCHES,
+ depending on the latching state of the page and tree where the cursor
+ is positioned; BTR_NO_LATCHES means that the cursor is not currently
+ positioned:
+ we say then that the cursor is detached; it can be restored to
+ attached if the old position was stored in old_rec */
+ btr_latch_mode latch_mode= BTR_NO_LATCHES;
+ /** if cursor position is stored, contains an initial segment of the
+ latest record cursor was positioned either on, before or after */
+ rec_t *old_rec= nullptr;
+ /** btr_cur.index()->n_core_fields when old_rec was copied */
+ uint16 old_n_core_fields= 0;
+ /** number of fields in old_rec */
+ uint16 old_n_fields= 0;
+ /** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on
+ whether cursor was on, before, or after the old_rec record */
+ btr_pcur_pos_t rel_pos= btr_pcur_pos_t(0);
+ /** buffer block when the position was stored */
+ buf::Block_hint block_when_stored;
+ /** the modify clock value of the buffer block when the cursor position
+ was stored */
+ ib_uint64_t modify_clock= 0;
+ /** btr_pcur_store_position() and btr_pcur_restore_position() state. */
+ enum pcur_pos_t pos_state= BTR_PCUR_NOT_POSITIONED;
+ page_cur_mode_t search_mode= PAGE_CUR_UNSUPP;
+ /** the transaction, if we know it; otherwise this field is not defined;
+ can ONLY BE USED in error prints in fatal assertion failures! */
+ trx_t *trx_if_known= nullptr;
+ /** a dynamically allocated buffer for old_rec */
+ byte *old_rec_buf= nullptr;
+ /** old_rec_buf size if old_rec_buf is not NULL */
+ ulint buf_size= 0;
+
+ /** Return the index of this persistent cursor */
+ dict_index_t *index() const { return(btr_cur.index()); }
+ MY_ATTRIBUTE((nonnull, warn_unused_result))
+ /** Restores the stored position of a persistent cursor bufferfixing
+ the page and obtaining the specified latches. If the cursor position
+ was saved when the
+ (1) cursor was positioned on a user record: this function restores the
+ position to the last record LESS OR EQUAL to the stored record;
+ (2) cursor was positioned on a page infimum record: restores the
+ position to the last record LESS than the user record which was the
+ successor of the page infimum;
+ (3) cursor was positioned on the page supremum: restores to the first
+ record GREATER than the user record which was the predecessor of the
+ supremum.
+ (4) cursor was positioned before the first or after the last in an
+ empty tree: restores to before first or after the last in the tree.
+ @param restore_latch_mode BTR_SEARCH_LEAF, ...
+ @param mtr mtr
+ @retval SAME_ALL cursor position on user rec and points on
+ the record with the same field values as in the stored record,
+ @retval SAME_UNIQ cursor position is on user rec and points on the
+ record with the same unique field values as in the stored record,
+ @retval NOT_SAME cursor position is not on user rec or points on
+ the record with not the same uniq field values as in the stored
+ @retval CORRUPTED if the index is corrupted */
+ restore_status restore_position(btr_latch_mode latch_mode, mtr_t *mtr);
+
+ /** Open the cursor on the first or last record.
+ @param first true=first record, false=last record
+ @param index B-tree
+ @param latch_mode which latches to acquire
+ @param mtr mini-transaction
+ @return error code */
+ dberr_t open_leaf(bool first, dict_index_t *index, btr_latch_mode latch_mode,
+ mtr_t *mtr)
+
+ {
+ this->latch_mode= BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
+ search_mode= first ? PAGE_CUR_G : PAGE_CUR_L;
+ pos_state= BTR_PCUR_IS_POSITIONED;
+ old_rec= nullptr;
+
+ return btr_cur.open_leaf(first, index,
+ BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode), mtr);
+ }
};
inline buf_block_t *btr_pcur_get_block(btr_pcur_t *cursor)
@@ -479,10 +439,9 @@ MY_ATTRIBUTE((nonnull, warn_unused_result))
inline
dberr_t
btr_pcur_open_on_user_rec(
- dict_index_t* index, /*!< in: index */
const dtuple_t* tuple, /*!< in: tuple on which search done */
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ... */
- ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or
+ btr_latch_mode latch_mode, /*!< in: BTR_SEARCH_LEAF or
BTR_MODIFY_LEAF */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent
cursor */
@@ -490,7 +449,7 @@ btr_pcur_open_on_user_rec(
{
ut_ad(mode == PAGE_CUR_GE || mode == PAGE_CUR_G);
ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF);
- if (dberr_t err= btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr))
+ if (dberr_t err= btr_pcur_open(tuple, mode, latch_mode, cursor, 0, mtr))
return err;
if (!btr_pcur_is_after_last_on_page(cursor) ||
btr_pcur_is_after_last_in_tree(cursor))
diff --git a/storage/innobase/include/btr0pcur.inl b/storage/innobase/include/btr0pcur.inl
index 82801f4426d..551f8f20fca 100644
--- a/storage/innobase/include/btr0pcur.inl
+++ b/storage/innobase/include/btr0pcur.inl
@@ -36,7 +36,6 @@ btr_pcur_get_rel_pos(
{
ut_ad(cursor);
ut_ad(cursor->old_rec);
- ut_ad(cursor->old_stored);
ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
|| cursor->pos_state == BTR_PCUR_IS_POSITIONED);
@@ -163,7 +162,7 @@ btr_pcur_move_to_next_on_page(
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- cursor->old_stored = false;
+ cursor->old_rec = nullptr;
return page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
}
@@ -177,7 +176,7 @@ btr_pcur_move_to_prev_on_page(
{
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- cursor->old_stored = false;
+ cursor->old_rec = nullptr;
return page_cur_move_to_prev(btr_pcur_get_page_cur(cursor));
}
@@ -196,7 +195,7 @@ btr_pcur_move_to_next_user_rec(
{
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- cursor->old_stored = false;
+ cursor->old_rec = nullptr;
loop:
if (btr_pcur_is_after_last_on_page(cursor)) {
if (btr_pcur_is_after_last_in_tree(cursor)
@@ -230,7 +229,7 @@ btr_pcur_move_to_next(
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- cursor->old_stored= false;
+ cursor->old_rec= nullptr;
if (btr_pcur_is_after_last_on_page(cursor))
return !btr_pcur_is_after_last_in_tree(cursor) &&
@@ -294,31 +293,17 @@ btr_pcur_init(
/*==========*/
btr_pcur_t* pcur) /*!< in: persistent cursor */
{
- pcur->old_stored = false;
pcur->old_rec_buf = NULL;
pcur->old_rec = NULL;
pcur->btr_cur.rtr_info = NULL;
}
-/** Free old_rec_buf.
-@param[in] pcur Persistent cursor holding old_rec to be freed. */
-UNIV_INLINE
-void
-btr_pcur_free(
- btr_pcur_t* pcur)
-{
- ut_free(pcur->old_rec_buf);
-}
-
/**************************************************************//**
Initializes and opens a persistent cursor to an index tree. */
inline
dberr_t
-btr_pcur_open_low(
-/*==============*/
- dict_index_t* index, /*!< in: index */
- ulint level, /*!< in: level in the btree */
+btr_pcur_open(
const dtuple_t* tuple, /*!< in: tuple on which search done */
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...;
NOTE that if the search is made using a unique
@@ -326,26 +311,24 @@ btr_pcur_open_low(
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
may end up on the previous page from the
record! */
- ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
+ btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
(0 if none) */
mtr_t* mtr) /*!< in: mtr */
{
- ut_ad(!index->is_spatial());
- btr_pcur_init(cursor);
+ ut_ad(!cursor->index()->is_spatial());
cursor->latch_mode= BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
cursor->search_mode= mode;
cursor->pos_state= BTR_PCUR_IS_POSITIONED;
cursor->trx_if_known= nullptr;
- return btr_cur_search_to_nth_level(index, level, tuple, mode, latch_mode,
+ return btr_cur_search_to_nth_level(0, tuple, mode, latch_mode,
btr_pcur_get_btr_cur(cursor),
mtr, autoinc);
}
/** Opens an persistent cursor to an index tree without initializing the
cursor.
-@param index index
@param tuple tuple on which search done
@param mode PAGE_CUR_L, ...; NOTE that if the search is made using a
unique prefix of a record, mode should be PAGE_CUR_LE, not
@@ -356,59 +339,21 @@ cursor.
@param mtr mini-transaction
@return DB_SUCCESS on success or error code otherwise. */
inline
-dberr_t btr_pcur_open_with_no_init(dict_index_t *index, const dtuple_t *tuple,
- page_cur_mode_t mode, ulint latch_mode,
+dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple,
+ page_cur_mode_t mode,
+ btr_latch_mode latch_mode,
btr_pcur_t *cursor, mtr_t *mtr)
{
cursor->latch_mode= BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode);
cursor->search_mode= mode;
cursor->pos_state= BTR_PCUR_IS_POSITIONED;
- cursor->old_stored= false;
cursor->trx_if_known= nullptr;
/* Search with the tree cursor */
- return btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
+ return btr_cur_search_to_nth_level(0, tuple, mode, latch_mode,
btr_pcur_get_btr_cur(cursor), mtr);
}
-/*****************************************************************//**
-Opens a persistent cursor at either end of an index. */
-UNIV_INLINE
-dberr_t
-btr_pcur_open_at_index_side(
-/*========================*/
- bool from_left, /*!< in: true if open to the low end,
- false if to the high end */
- dict_index_t* index, /*!< in: index */
- ulint latch_mode, /*!< in: latch mode */
- btr_pcur_t* pcur, /*!< in/out: cursor */
- bool init_pcur, /*!< in: whether to initialize pcur */
- ulint level, /*!< in: level to search for
- (0=leaf) */
- mtr_t* mtr) /*!< in/out: mini-transaction */
-{
- dberr_t err = DB_SUCCESS;
-
- pcur->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
-
- pcur->search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L;
-
- if (init_pcur) {
- btr_pcur_init(pcur);
- }
-
- err = btr_cur_open_at_index_side(
- from_left, index, latch_mode,
- btr_pcur_get_btr_cur(pcur), level, mtr);
- pcur->pos_state = BTR_PCUR_IS_POSITIONED;
-
- pcur->old_stored = false;
-
- pcur->trx_if_known = NULL;
-
- return (err);
-}
-
/**************************************************************//**
Frees the possible memory heap of a persistent cursor and sets the latch
mode of the persistent cursor to BTR_NO_LATCHES.
@@ -425,25 +370,21 @@ btr_pcur_close(
/*===========*/
btr_pcur_t* cursor) /*!< in: persistent cursor */
{
- ut_free(cursor->old_rec_buf);
-
- if (cursor->btr_cur.rtr_info) {
- rtr_clean_rtr_info(cursor->btr_cur.rtr_info, true);
- cursor->btr_cur.rtr_info = NULL;
- }
+ ut_free(cursor->old_rec_buf);
- cursor->old_rec = NULL;
- cursor->old_rec_buf = NULL;
- cursor->btr_cur.page_cur.rec = NULL;
- cursor->btr_cur.page_cur.block = NULL;
+ if (cursor->btr_cur.rtr_info)
+ rtr_clean_rtr_info(cursor->btr_cur.rtr_info, true);
- cursor->old_rec = NULL;
- cursor->old_stored = false;
+ cursor->btr_cur.rtr_info= nullptr;
+ cursor->old_rec = nullptr;
+ cursor->old_rec_buf = nullptr;
+ cursor->btr_cur.page_cur.rec = nullptr;
+ cursor->btr_cur.page_cur.block = nullptr;
- cursor->latch_mode = BTR_NO_LATCHES;
- cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
+ cursor->latch_mode = BTR_NO_LATCHES;
+ cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
- cursor->trx_if_known = NULL;
+ cursor->trx_if_known = nullptr;
}
/*********************************************************//**
@@ -459,5 +400,5 @@ btr_pcur_move_before_first_on_page(
page_cur_set_before_first(btr_pcur_get_block(cursor),
btr_pcur_get_page_cur(cursor));
- cursor->old_stored = false;
+ cursor->old_rec = nullptr;
}
diff --git a/storage/innobase/include/btr0types.h b/storage/innobase/include/btr0types.h
index 83c374e2561..6118bfbc128 100644
--- a/storage/innobase/include/btr0types.h
+++ b/storage/innobase/include/btr0types.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2018, 2019, MariaDB Corporation.
+Copyright (c) 2018, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -24,8 +24,7 @@ The index tree general types
Created 2/17/1996 Heikki Tuuri
*************************************************************************/
-#ifndef btr0types_h
-#define btr0types_h
+#pragma once
#include "page0types.h"
#include "rem0types.h"
@@ -56,4 +55,93 @@ in the index record. */
#define BTR_EXTERN_LOCAL_STORED_MAX_SIZE \
(BTR_EXTERN_FIELD_REF_SIZE * 2)
-#endif
+/** Latching modes for btr_cur_search_to_nth_level(). */
+enum btr_latch_mode {
+ /** Search a record on a leaf page and S-latch it. */
+ BTR_SEARCH_LEAF = RW_S_LATCH,
+ /** (Prepare to) modify a record on a leaf page and X-latch it. */
+ BTR_MODIFY_LEAF = RW_X_LATCH,
+ /** Obtain no latches. */
+ BTR_NO_LATCHES = RW_NO_LATCH,
+ /** Search the previous record. */
+ BTR_SEARCH_PREV = 4 | BTR_SEARCH_LEAF,
+ /** Modify the previous record. */
+ BTR_MODIFY_PREV = 4 | BTR_MODIFY_LEAF,
+ /** Start searching the entire B-tree. */
+ BTR_SEARCH_TREE = 8 | BTR_SEARCH_LEAF,
+ /** Start modifying1 the entire B-tree. */
+ BTR_MODIFY_TREE = 8 | BTR_MODIFY_LEAF,
+ /** Continue searching the entire B-tree. */
+ BTR_CONT_SEARCH_TREE = 4 | BTR_SEARCH_TREE,
+ /** Continue modifying the entire B-tree. */
+ BTR_CONT_MODIFY_TREE = 4 | BTR_MODIFY_TREE,
+
+ /* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually
+ exclusive. */
+ /** The search tuple will be inserted to the secondary index
+ at the searched position. When the leaf page is not in the
+ buffer pool, try to use the change buffer. */
+ BTR_INSERT = 64,
+
+ /** Try to delete mark a secondary index leaf page record at
+ the searched position using the change buffer when the page is
+ not in the buffer pool. */
+ BTR_DELETE_MARK = 128,
+
+ /** Try to purge the record using the change buffer when the
+ secondary index leaf page is not in the buffer pool. */
+ BTR_DELETE = BTR_INSERT | BTR_DELETE_MARK,
+
+ /** The caller is already holding dict_index_t::lock S-latch. */
+ BTR_ALREADY_S_LATCHED = 256,
+ /** Search and S-latch a leaf page, assuming that the
+ dict_index_t::lock S-latch is being held. */
+ BTR_SEARCH_LEAF_ALREADY_S_LATCHED = BTR_SEARCH_LEAF
+ | BTR_ALREADY_S_LATCHED,
+ /** Search the entire index tree, assuming that the
+ dict_index_t::lock S-latch is being held. */
+ BTR_SEARCH_TREE_ALREADY_S_LATCHED = BTR_SEARCH_TREE
+ | BTR_ALREADY_S_LATCHED,
+ /** Search and X-latch a leaf page, assuming that the
+ dict_index_t::lock is being held in non-exclusive mode. */
+ BTR_MODIFY_LEAF_ALREADY_LATCHED = BTR_MODIFY_LEAF
+ | BTR_ALREADY_S_LATCHED,
+
+ /** Attempt to delete-mark a secondary index record. */
+ BTR_DELETE_MARK_LEAF = BTR_MODIFY_LEAF | BTR_DELETE_MARK,
+ /** Attempt to delete-mark a secondary index record
+ while holding the dict_index_t::lock S-latch. */
+ BTR_DELETE_MARK_LEAF_ALREADY_S_LATCHED = BTR_DELETE_MARK_LEAF
+ | BTR_ALREADY_S_LATCHED,
+ /** Attempt to purge a secondary index record. */
+ BTR_PURGE_LEAF = BTR_MODIFY_LEAF | BTR_DELETE,
+ /** Attempt to purge a secondary index record
+ while holding the dict_index_t::lock S-latch. */
+ BTR_PURGE_LEAF_ALREADY_S_LATCHED = BTR_PURGE_LEAF
+ | BTR_ALREADY_S_LATCHED,
+
+ /** In the case of BTR_MODIFY_TREE, the caller specifies
+ the intention to delete record only. It is used to optimize
+ block->lock range.*/
+ BTR_LATCH_FOR_DELETE = 512,
+
+ /** In the case of BTR_MODIFY_TREE, the caller specifies
+ the intention to delete record only. It is used to optimize
+ block->lock range.*/
+ BTR_LATCH_FOR_INSERT = 1024,
+
+ /** Attempt to delete a record in the tree. */
+ BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
+
+ /** Attempt to insert a record into the tree. */
+ BTR_INSERT_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_INSERT,
+
+ /** This flag ORed to BTR_INSERT says that we can ignore possible
+ UNIQUE definition on secondary indexes when we decide if we can use
+ the insert buffer to speed up inserts */
+ BTR_IGNORE_SEC_UNIQUE = 2048,
+ /** Rollback in spatial index */
+ BTR_RTREE_UNDO_INS = 4096,
+ /** Try to delete mark a spatial index record */
+ BTR_RTREE_DELETE_MARK = 8192
+};
diff --git a/storage/innobase/include/dyn0buf.h b/storage/innobase/include/dyn0buf.h
index cb8b998f0ea..06af4dcca88 100644
--- a/storage/innobase/include/dyn0buf.h
+++ b/storage/innobase/include/dyn0buf.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2018, 2020, MariaDB Corporation.
+Copyright (c) 2018, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -317,63 +317,9 @@ public:
Iterate over each block and call the functor.
@return false if iteration was terminated. */
template <typename Functor>
- bool for_each_block(Functor& functor) const
- {
- for (list_t::iterator it = m_list.begin(), end = m_list.end();
- it != end; ++it) {
-
- if (!functor(&*it)) {
- return false;
- }
- }
-
- return(true);
- }
-
- /**
- Iterate over each block and call the functor.
- @return false if iteration was terminated. */
- template <typename Functor>
bool for_each_block(const Functor& functor) const
{
- for (typename list_t::iterator it = m_list.begin(),
- end = m_list.end();
- it != end; ++it) {
-
- if (!functor(&*it)) {
- return false;
- }
- }
-
- return(true);
- }
-
- /**
- Iterate over all the blocks in reverse and call the iterator
- @return false if iteration was terminated. */
- template <typename Functor>
- bool for_each_block_in_reverse(Functor& functor) const
- {
- for (list_t::reverse_iterator it = m_list.rbegin(),
- end = m_list.rend();
- it != end; ++it) {
-
- if (!functor(&*it)) {
- return false;
- }
- }
-
- return(true);
- }
-
- /**
- Iterate over all the blocks in reverse and call the iterator
- @return false if iteration was terminated. */
- template <typename Functor>
- bool for_each_block_in_reverse(const Functor& functor) const
- {
- for (list_t::reverse_iterator it = m_list.rbegin(),
- end = m_list.rend();
+ for (list_t::iterator it = m_list.begin(), end = m_list.end();
it != end; ++it) {
if (!functor(&*it)) {
diff --git a/storage/innobase/include/gis0rtree.h b/storage/innobase/include/gis0rtree.h
index 8cd5e384530..777f2432c93 100644
--- a/storage/innobase/include/gis0rtree.h
+++ b/storage/innobase/include/gis0rtree.h
@@ -256,23 +256,14 @@ rtr_get_mbr_from_tuple(
rtr_mbr* mbr); /*!< out: mbr to fill */
/* Get the rtree page father.
-@param[in] offsets work area for the return value
-@param[in] index rtree index
-@param[in] block child page in the index
@param[in,out] mtr mtr
@param[in] sea_cur search cursor, contains information
about parent nodes in search
-@param[out] cursor cursor on node pointer record,
+@param[in,out] cursor cursor on node pointer record,
its page x-latched
@return whether the cursor was successfully positioned */
-bool
-rtr_page_get_father(
- dict_index_t* index,
- buf_block_t* block,
- mtr_t* mtr,
- btr_cur_t* sea_cur,
- btr_cur_t* cursor)
- MY_ATTRIBUTE((nonnull(1,2,3,5), warn_unused_result));
+bool rtr_page_get_father(mtr_t *mtr, btr_cur_t *sea_cur, btr_cur_t *cursor)
+ MY_ATTRIBUTE((nonnull(1,3), warn_unused_result));
/************************************************************//**
Returns the father block to a page. It is assumed that mtr holds
@@ -283,8 +274,6 @@ rtr_page_get_father_block(
/*======================*/
rec_offs* offsets,/*!< in: work area for the return value */
mem_heap_t* heap, /*!< in: memory heap to use */
- dict_index_t* index, /*!< in: b-tree index */
- buf_block_t* block, /*!< in: child page in the index */
mtr_t* mtr, /*!< in: mtr */
btr_cur_t* sea_cur,/*!< in: search cursor, contains information
about parent nodes in search */
@@ -298,7 +287,7 @@ rtr_store_parent_path(
/*==================*/
const buf_block_t* block, /*!< in: block of the page */
btr_cur_t* btr_cur,/*!< in/out: persistent cursor */
- ulint latch_mode,
+ btr_latch_mode latch_mode,
/*!< in: latch_mode */
ulint level, /*!< in: index level */
mtr_t* mtr); /*!< in: mtr */
@@ -310,7 +299,7 @@ bool
rtr_pcur_open(
dict_index_t* index, /*!< in: index */
const dtuple_t* tuple, /*!< in: tuple on which search done */
- ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
+ btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
mtr_t* mtr) /*!< in: mtr */
MY_ATTRIBUTE((warn_unused_result));
@@ -432,7 +421,6 @@ rtr_check_same_block(
btr_cur_t* cur, /*!< in/out: position at the parent entry
pointing to the child if successful */
buf_block_t* parentb,/*!< in: parent page to check */
- buf_block_t* childb, /*!< in: child Page */
mem_heap_t* heap); /*!< in: memory heap */
/*********************************************************************//**
diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h
index e6f72b05087..c246b2ef513 100644
--- a/storage/innobase/include/ibuf0ibuf.h
+++ b/storage/innobase/include/ibuf0ibuf.h
@@ -30,7 +30,6 @@ Created 7/19/1997 Heikki Tuuri
#include "mtr0mtr.h"
#include "dict0mem.h"
#include "fsp0fsp.h"
-#include "ibuf0types.h"
/** Default value for maximum on-disk size of change buffer in terms
of percentage of the buffer pool. */
@@ -61,6 +60,37 @@ enum ibuf_use_t {
/** Operations that can currently be buffered. */
extern ulong innodb_change_buffering;
+/** Insert buffer struct */
+struct ibuf_t{
+ Atomic_relaxed<ulint> size; /*!< current size of the ibuf index
+ tree, in pages */
+ Atomic_relaxed<ulint> max_size; /*!< recommended maximum size of the
+ ibuf index tree, in pages */
+ ulint seg_size; /*!< allocated pages of the file
+ segment containing ibuf header and
+ tree */
+ bool empty; /*!< Protected by the page
+ latch of the root page of the
+ insert buffer tree
+ (FSP_IBUF_TREE_ROOT_PAGE_NO). true
+ if and only if the insert
+ buffer tree is empty. */
+ ulint free_list_len; /*!< length of the free list */
+ ulint height; /*!< tree height */
+ dict_index_t* index; /*!< insert buffer index */
+
+ /** number of pages merged */
+ Atomic_counter<ulint> n_merges;
+ Atomic_counter<ulint> n_merged_ops[IBUF_OP_COUNT];
+ /*!< number of operations of each type
+ merged to index pages */
+ Atomic_counter<ulint> n_discarded_ops[IBUF_OP_COUNT];
+ /*!< number of operations of each type
+ discarded without merging due to the
+ tablespace being deleted or the
+ index being dropped */
+};
+
/** The insert buffer control structure */
extern ibuf_t ibuf;
@@ -339,9 +369,9 @@ void ibuf_delete_for_discarded_space(uint32_t space);
/** Contract the change buffer by reading pages to the buffer pool.
@return a lower limit for the combined size in bytes of entries which
-will be merged from ibuf trees to the pages read, 0 if ibuf is
-empty */
-ulint ibuf_merge_all();
+will be merged from ibuf trees to the pages read
+@retval 0 if ibuf.empty */
+ulint ibuf_contract();
/** Contracts insert buffer trees by reading pages referring to space_id
to the buffer pool.
diff --git a/storage/innobase/include/ibuf0ibuf.inl b/storage/innobase/include/ibuf0ibuf.inl
index 2d8265d2206..12aa1ca6837 100644
--- a/storage/innobase/include/ibuf0ibuf.inl
+++ b/storage/innobase/include/ibuf0ibuf.inl
@@ -65,37 +65,6 @@ ibuf_mtr_commit(
mtr_commit(mtr);
}
-/** Insert buffer struct */
-struct ibuf_t{
- ulint size; /*!< current size of the ibuf index
- tree, in pages */
- ulint max_size; /*!< recommended maximum size of the
- ibuf index tree, in pages */
- ulint seg_size; /*!< allocated pages of the file
- segment containing ibuf header and
- tree */
- bool empty; /*!< Protected by the page
- latch of the root page of the
- insert buffer tree
- (FSP_IBUF_TREE_ROOT_PAGE_NO). true
- if and only if the insert
- buffer tree is empty. */
- ulint free_list_len; /*!< length of the free list */
- ulint height; /*!< tree height */
- dict_index_t* index; /*!< insert buffer index */
-
- /** number of pages merged */
- Atomic_counter<ulint> n_merges;
- Atomic_counter<ulint> n_merged_ops[IBUF_OP_COUNT];
- /*!< number of operations of each type
- merged to index pages */
- Atomic_counter<ulint> n_discarded_ops[IBUF_OP_COUNT];
- /*!< number of operations of each type
- discarded without merging due to the
- tablespace being deleted or the
- index being dropped */
-};
-
/************************************************************************//**
Sets the free bit of the page in the ibuf bitmap. This is done in a separate
mini-transaction, hence this operation does not restrict further work to only
diff --git a/storage/innobase/include/ibuf0types.h b/storage/innobase/include/ibuf0types.h
deleted file mode 100644
index 6b7c47208a0..00000000000
--- a/storage/innobase/include/ibuf0types.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*****************************************************************************
-
-Copyright (c) 1997, 2009, Oracle and/or its affiliates. All Rights Reserved.
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; version 2 of the License.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
-
-*****************************************************************************/
-
-/**************************************************//**
-@file include/ibuf0types.h
-Insert buffer global types
-
-Created 7/29/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef ibuf0types_h
-#define ibuf0types_h
-
-struct ibuf_t;
-
-#endif
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h
index ef4465c41cd..7f5eb482e97 100644
--- a/storage/innobase/include/log0log.h
+++ b/storage/innobase/include/log0log.h
@@ -214,6 +214,11 @@ public:
/** number of std::swap(buf, flush_buf) and writes from buf to log;
protected by latch.wr_lock() */
ulint write_to_log;
+
+ /** Log sequence number when a log file overwrite (broken crash recovery)
+ was noticed. Protected by latch.wr_lock(). */
+ lsn_t overwrite_warned;
+
/** innodb_log_buffer_size (size of buf and flush_buf, in bytes) */
size_t buf_size;
diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h
index 21d0cfbb5a1..abc1f65e692 100644
--- a/storage/innobase/include/mtr0mtr.h
+++ b/storage/innobase/include/mtr0mtr.h
@@ -28,6 +28,8 @@ Created 11/26/1995 Heikki Tuuri
#include "fil0fil.h"
#include "dyn0buf.h"
+#include "buf0buf.h"
+#include <vector>
/** Start a mini-transaction. */
#define mtr_start(m) (m)->start()
@@ -48,11 +50,6 @@ savepoint. */
@return old mode */
#define mtr_set_log_mode(m, d) (m)->set_log_mode((d))
-/** Release an object in the memo stack.
-@return true if released */
-#define mtr_memo_release(m, o, t) \
- (m)->memo_release((o), (t))
-
#ifdef UNIV_PFS_RWLOCK
# define mtr_s_lock_index(i,m) (m)->s_lock(__FILE__, __LINE__, &(i)->lock)
# define mtr_x_lock_index(i,m) (m)->x_lock(__FILE__, __LINE__, &(i)->lock)
@@ -66,19 +63,16 @@ savepoint. */
#define mtr_release_block_at_savepoint(m, s, b) \
(m)->release_block_at_savepoint((s), (b))
-#define mtr_block_sx_latch_at_savepoint(m, s, b) \
- (m)->sx_latch_at_savepoint((s), (b))
-
-#define mtr_block_x_latch_at_savepoint(m, s, b) \
- (m)->x_latch_at_savepoint((s), (b))
-
/** Mini-transaction memo stack slot. */
-struct mtr_memo_slot_t {
- /** pointer to the object */
- void* object;
-
- /** type of the stored object */
- mtr_memo_type_t type;
+struct mtr_memo_slot_t
+{
+ /** pointer to the object, or nullptr if released */
+ void *object;
+ /** type of the stored object */
+ mtr_memo_type_t type;
+
+ /** Release the object */
+ void release() const;
};
/** Mini-transaction handle and buffer */
@@ -89,14 +83,19 @@ struct mtr_t {
/** Commit the mini-transaction. */
void commit();
- /** Release latches till savepoint. To simplify the code only
- MTR_MEMO_S_LOCK and MTR_MEMO_PAGE_S_FIX slot types are allowed to be
- released, otherwise it would be neccesary to add one more argument in the
- function to point out what slot types are allowed for rollback, and this
- would be overengineering as currently the function is used only in one place
- in the code.
- @param savepoint savepoint, can be obtained with get_savepoint */
- void rollback_to_savepoint(ulint savepoint);
+ /** Release latches of unmodified buffer pages.
+ @param begin first slot to release
+ @param end last slot to release, or get_savepoint() */
+ void rollback_to_savepoint(ulint begin, ulint end);
+
+ /** Release latches of unmodified buffer pages.
+ @param begin first slot to release */
+ void rollback_to_savepoint(ulint begin)
+ { rollback_to_savepoint(begin, m_memo->size()); }
+
+ /** Release the last acquired buffer page latch. */
+ void release_last_page()
+ { auto s= m_memo->size(); rollback_to_savepoint(s - 1, s); }
/** Commit a mini-transaction that is shrinking a tablespace.
@param space tablespace that is being shrunk */
@@ -118,26 +117,89 @@ struct mtr_t {
lsn_t commit_files(lsn_t checkpoint_lsn= 0);
/** @return mini-transaction savepoint (current size of m_memo) */
- ulint get_savepoint() const { ut_ad(is_active()); return m_memo.size(); }
+ ulint get_savepoint() const
+ {
+ ut_ad(is_active());
+ return m_memo ? m_memo->size() : 0;
+ }
- /** Release the (index tree) s-latch stored in an mtr memo after a
- savepoint.
- @param savepoint value returned by @see set_savepoint.
- @param lock latch to release */
- inline void release_s_latch_at_savepoint(
- ulint savepoint,
- index_lock* lock);
+ /** Release the (index tree) s-latch stored in an mtr memo after a savepoint.
+ @param savepoint value returned by get_savepoint()
+ @param lock index latch to release */
+ void release_s_latch_at_savepoint(ulint savepoint, index_lock *lock)
+ {
+ ut_ad(is_active());
+ mtr_memo_slot_t &slot= m_memo->at(savepoint);
+ ut_ad(slot.object == lock);
+ ut_ad(slot.type == MTR_MEMO_S_LOCK);
+ slot.object= nullptr;
+ lock->s_unlock();
+ }
+ /** Release the block in an mtr memo after a savepoint. */
+ void release_block_at_savepoint(ulint savepoint, buf_block_t *block)
+ {
+ ut_ad(is_active());
+ mtr_memo_slot_t &slot= m_memo->at(savepoint);
+ ut_ad(slot.object == block);
+ ut_ad(!(slot.type & MTR_MEMO_MODIFY));
+ slot.object= nullptr;
+ block->page.unfix();
+
+ switch (slot.type) {
+ case MTR_MEMO_PAGE_S_FIX:
+ block->page.lock.s_unlock();
+ break;
+ case MTR_MEMO_PAGE_SX_FIX:
+ case MTR_MEMO_PAGE_X_FIX:
+ block->page.lock.u_or_x_unlock(slot.type == MTR_MEMO_PAGE_SX_FIX);
+ break;
+ default:
+ break;
+ }
+ }
- /** Release the block in an mtr memo after a savepoint. */
- inline void release_block_at_savepoint(
- ulint savepoint,
- buf_block_t* block);
+ /** @return if we are about to make a clean buffer block dirty */
+ static bool is_block_dirtied(const buf_page_t &b)
+ {
+ ut_ad(b.in_file());
+ ut_ad(b.frame);
+ ut_ad(b.buf_fix_count());
+ return b.oldest_modification() <= 1 && b.id().space() < SRV_TMP_SPACE_ID;
+ }
- /** SX-latch a not yet latched block after a savepoint. */
- inline void sx_latch_at_savepoint(ulint savepoint, buf_block_t* block);
+ /** X-latch a not yet latched block after a savepoint. */
+ void x_latch_at_savepoint(ulint savepoint, buf_block_t *block)
+ {
+ ut_ad(is_active());
+ ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX |
+ MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
+ mtr_memo_slot_t &slot= m_memo->at(savepoint);
+ ut_ad(slot.object == block);
+ ut_ad(slot.type == MTR_MEMO_BUF_FIX);
+ slot.type= MTR_MEMO_PAGE_X_FIX;
+ block->page.lock.x_lock();
+ ut_ad(!block->page.is_io_fixed());
+
+ if (!m_made_dirty)
+ m_made_dirty= is_block_dirtied(block->page);
+ }
- /** X-latch a not yet latched block after a savepoint. */
- inline void x_latch_at_savepoint(ulint savepoint, buf_block_t* block);
+ /** U-latch a not yet latched block after a savepoint. */
+ void sx_latch_at_savepoint(ulint savepoint, buf_block_t *block)
+ {
+ ut_ad(is_active());
+ ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX |
+ MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
+ mtr_memo_slot_t &slot= m_memo->at(savepoint);
+ ut_ad(slot.object == block);
+ ut_ad(slot.type == MTR_MEMO_BUF_FIX);
+ slot.type= MTR_MEMO_PAGE_SX_FIX;
+ block->page.lock.u_lock();
+ ut_ad(!block->page.is_io_fixed());
+
+ if (!m_made_dirty)
+ m_made_dirty= is_block_dirtied(block->page);
+ }
/** @return the logging mode */
mtr_log_t get_log_mode() const
@@ -291,19 +353,17 @@ struct mtr_t {
/** Acquire an exclusive tablespace latch.
@param space tablespace */
void x_lock_space(fil_space_t *space);
- /** Release an object in the memo stack.
- @param object object
- @param type object type
- @return bool if lock released */
- bool memo_release(const void *object, ulint type);
- /** Release a page latch.
- @param[in] ptr pointer to within a page frame
- @param[in] type object type: MTR_MEMO_PAGE_X_FIX, ... */
- void release_page(const void *ptr, mtr_memo_type_t type);
+
+ /** Release an index latch. */
+ void release(const index_lock &lock) { release(&lock); }
+ /** Release a latch to an unmodified page. */
+ void release(const buf_block_t &block) { release(&block); }
/** Note that the mini-transaction will modify data. */
void flag_modified() { m_modifications = true; }
private:
+ /** Release an unmodified object. */
+ void release(const void *object);
/** Mark the given latched page as modified.
@param block page that will be modified */
void modify(const buf_block_t& block);
@@ -338,73 +398,93 @@ public:
@param rw_latch RW_S_LATCH, RW_SX_LATCH, RW_X_LATCH, RW_NO_LATCH */
void page_lock(buf_block_t *block, ulint rw_latch);
+ /** Acquire a latch on a buffer-fixed buffer pool block.
+ @param savepoint savepoint location of the buffer-fixed block
+ @param rw_latch latch to acquire */
+ void upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch);
+
/** Register a page latch on a buffer-fixed block was buffer-fixed.
@param latch latch type */
void u_lock_register(ulint savepoint)
{
- mtr_memo_slot_t *slot= m_memo.at<mtr_memo_slot_t*>(savepoint);
- ut_ad(slot->type == MTR_MEMO_BUF_FIX);
- slot->type= MTR_MEMO_PAGE_SX_FIX;
+ mtr_memo_slot_t &slot= m_memo->at(savepoint);
+ ut_ad(slot.type == MTR_MEMO_BUF_FIX);
+ slot.type= MTR_MEMO_PAGE_SX_FIX;
+ }
+
+ /** Register a page latch on a buffer-fixed block was buffer-fixed.
+ @param latch latch type */
+ void s_lock_register(ulint savepoint)
+ {
+ mtr_memo_slot_t &slot= m_memo->at(savepoint);
+ ut_ad(slot.type == MTR_MEMO_BUF_FIX);
+ slot.type= MTR_MEMO_PAGE_S_FIX;
}
/** Upgrade U locks on a block to X */
void page_lock_upgrade(const buf_block_t &block);
- /** Upgrade X lock to X */
+ /** Upgrade U lock to X */
void lock_upgrade(const index_lock &lock);
/** Check if we are holding tablespace latch
@param space tablespace to search for
@param shared whether to look for shared latch, instead of exclusive
@return whether space.latch is being held */
- bool memo_contains(const fil_space_t& space, bool shared= false)
+ bool memo_contains(const fil_space_t& space, bool shared= false) const
MY_ATTRIBUTE((warn_unused_result));
#ifdef UNIV_DEBUG
/** Check if we are holding an rw-latch in this mini-transaction
@param lock latch to search for
@param type held latch type
@return whether (lock,type) is contained */
- bool memo_contains(const index_lock &lock, mtr_memo_type_t type)
+ bool memo_contains(const index_lock &lock, mtr_memo_type_t type) const
MY_ATTRIBUTE((warn_unused_result));
- /** Check if memo contains the given item.
- @param object object to search
- @param flags specify types of object (can be ORred) of
- MTR_MEMO_PAGE_S_FIX ... values
- @return true if contains */
- bool memo_contains_flagged(const void* ptr, ulint flags) const;
-
- /** Check if memo contains the given page.
- @param[in] ptr pointer to within buffer frame
- @param[in] flags specify types of object with OR of
- MTR_MEMO_PAGE_S_FIX... values
- @return the block
- @retval NULL if not found */
- buf_block_t* memo_contains_page_flagged(
- const byte* ptr,
- ulint flags) const;
-
- /** @return true if mini-transaction contains modifications. */
- bool has_modifications() const { return m_modifications; }
+ /** Check if memo contains an index or buffer block latch.
+ @param object object to search
+ @param flags specify types of object latches
+ @return true if contains */
+ bool memo_contains_flagged(const void *object, ulint flags) const
+ MY_ATTRIBUTE((warn_unused_result, nonnull));
+
+ /** Check if memo contains the given page.
+ @param ptr pointer to within page frame
+ @param flags types latch to look for
+ @return the block
+ @retval nullptr if not found */
+ buf_block_t *memo_contains_page_flagged(const byte *ptr, ulint flags) const;
+
+ /** @return true if mini-transaction contains modifications. */
+ bool has_modifications() const { return m_modifications; }
#endif /* UNIV_DEBUG */
- /** @return true if a record was added to the mini-transaction */
- bool is_dirty() const { return m_made_dirty; }
-
- /** Push an object to an mtr memo stack.
- @param object object
- @param type object type: MTR_MEMO_S_LOCK, ... */
- inline void memo_push(void* object, mtr_memo_type_t type);
-
- /** Check if this mini-transaction is dirtying a clean page.
- @param block block being x-fixed
- @return true if the mtr is dirtying a clean page. */
- static inline bool is_block_dirtied(const buf_block_t* block)
- MY_ATTRIBUTE((warn_unused_result));
+ /** Push an object to an mtr memo stack.
+ @param object object
+ @param type object type: MTR_MEMO_S_LOCK, ... */
+ void memo_push(void *object, mtr_memo_type_t type) __attribute__((nonnull))
+ {
+ ut_ad(is_active());
+ /* If this mtr has U or X latched a clean page then we set
+ the m_made_dirty flag. This tells us if we need to
+ grab log_sys.flush_order_mutex at mtr_t::commit() so that we
+ can insert the dirtied page into the buf_pool.flush_list.
+
+ FIXME: Do this only when the MTR_MEMO_MODIFY flag is set! */
+ if (!m_made_dirty &&
+ (type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)))
+ m_made_dirty=
+ is_block_dirtied(*static_cast<const buf_page_t*>(object));
+
+ if (!m_memo)
+ m_memo= new std::vector<mtr_memo_slot_t>(1, {object, type});
+ else
+ m_memo->emplace_back(mtr_memo_slot_t{object, type});
+ }
/** @return the size of the log is empty */
size_t get_log_size() const { return m_log.size(); }
/** @return whether the log and memo are empty */
- bool is_empty() const { return m_memo.size() == 0 && m_log.size() == 0; }
+ bool is_empty() const { return !get_savepoint() && !get_log_size(); }
/** Write an OPT_PAGE_CHECKSUM record. */
inline void page_checksum(const buf_page_t &bpage);
@@ -670,6 +750,8 @@ private:
@return {start_lsn,flush_ahead} */
std::pair<lsn_t,page_flush_ahead> finish_write(size_t len);
+ /** Release all latches. */
+ void release();
/** Release the resources */
inline void release_resources();
@@ -727,7 +809,7 @@ private:
#endif /* UNIV_DEBUG */
/** acquired dict_index_t::lock, fil_space_t::latch, buf_block_t */
- mtr_buf_t m_memo;
+ std::vector<mtr_memo_slot_t> *m_memo= nullptr;
/** mini-transaction log */
mtr_buf_t m_log;
@@ -743,5 +825,3 @@ private:
/** set of freed page ids */
range_set *m_freed_pages= nullptr;
};
-
-#include "mtr0mtr.inl"
diff --git a/storage/innobase/include/mtr0mtr.inl b/storage/innobase/include/mtr0mtr.inl
deleted file mode 100644
index 1368cca0efd..00000000000
--- a/storage/innobase/include/mtr0mtr.inl
+++ /dev/null
@@ -1,179 +0,0 @@
-/*****************************************************************************
-
-Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2022, MariaDB Corporation.
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; version 2 of the License.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
-
-*****************************************************************************/
-
-/**************************************************//**
-@file include/mtr0mtr.ic
-Mini-transaction buffer
-
-Created 11/26/1995 Heikki Tuuri
-*******************************************************/
-
-#include "buf0buf.h"
-
-/** Check if a mini-transaction is dirtying a clean page.
-@return true if the mtr is dirtying a clean page. */
-inline bool mtr_t::is_block_dirtied(const buf_block_t *block)
-{
- ut_ad(block->page.in_file());
- ut_ad(block->page.frame);
- ut_ad(block->page.buf_fix_count());
- return block->page.oldest_modification() <= 1 &&
- block->page.id().space() < SRV_TMP_SPACE_ID;
-}
-
-/**
-Pushes an object to an mtr memo stack. */
-void
-mtr_t::memo_push(void* object, mtr_memo_type_t type)
-{
- ut_ad(is_active());
- ut_ad(object != NULL);
- ut_ad(type >= MTR_MEMO_PAGE_S_FIX);
- ut_ad(type <= MTR_MEMO_SPACE_S_LOCK);
- ut_ad(type == MTR_MEMO_PAGE_X_MODIFY || ut_is_2pow(type));
-
- /* If this mtr has U or X latched a clean page then we set
- the m_made_dirty flag. This tells us if we need to
- grab log_sys.flush_order_mutex at mtr_t::commit() so that we
- can insert the dirtied page into the buf_pool.flush_list. */
-
- if (!m_made_dirty
- && (type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))) {
-
- m_made_dirty = is_block_dirtied(
- reinterpret_cast<const buf_block_t*>(object));
- }
-
- mtr_memo_slot_t* slot = m_memo.push<mtr_memo_slot_t*>(sizeof(*slot));
-
- slot->type = type;
- slot->object = object;
-}
-
-/**
-Releases the (index tree) s-latch stored in an mtr memo after a
-savepoint. */
-void
-mtr_t::release_s_latch_at_savepoint(
- ulint savepoint,
- index_lock* lock)
-{
- ut_ad(is_active());
- ut_ad(m_memo.size() > savepoint);
-
- mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
-
- ut_ad(slot->object == lock);
- ut_ad(slot->type == MTR_MEMO_S_LOCK);
-
- lock->s_unlock();
-
- slot->object = NULL;
-}
-
-/**
-SX-latches the not yet latched block after a savepoint. */
-
-void
-mtr_t::sx_latch_at_savepoint(
- ulint savepoint,
- buf_block_t* block)
-{
- ut_ad(is_active());
- ut_ad(m_memo.size() > savepoint);
-
- ut_ad(!memo_contains_flagged(
- block,
- MTR_MEMO_PAGE_S_FIX
- | MTR_MEMO_PAGE_X_FIX
- | MTR_MEMO_PAGE_SX_FIX));
-
- mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
-
- ut_ad(slot->object == block);
- ut_ad(slot->type == MTR_MEMO_BUF_FIX); /* == RW_NO_LATCH */
- slot->type = MTR_MEMO_PAGE_SX_FIX;
-
- block->page.lock.u_lock();
- ut_ad(!block->page.is_io_fixed());
-
- if (!m_made_dirty) {
- m_made_dirty = is_block_dirtied(block);
- }
-}
-
-/**
-X-latches the not yet latched block after a savepoint. */
-
-void
-mtr_t::x_latch_at_savepoint(
- ulint savepoint,
- buf_block_t* block)
-{
- ut_ad(is_active());
- ut_ad(m_memo.size() > savepoint);
-
- ut_ad(!memo_contains_flagged(
- block,
- MTR_MEMO_PAGE_S_FIX
- | MTR_MEMO_PAGE_X_FIX
- | MTR_MEMO_PAGE_SX_FIX));
-
- mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
-
- ut_ad(slot->object == block);
- ut_ad(slot->type == MTR_MEMO_BUF_FIX); /* == RW_NO_LATCH */
- slot->type = MTR_MEMO_PAGE_X_FIX;
-
- block->page.lock.x_lock();
- ut_ad(!block->page.is_io_fixed());
-
- if (!m_made_dirty) {
- m_made_dirty = is_block_dirtied(block);
- }
-}
-
-/**
-Releases the block in an mtr memo after a savepoint. */
-
-void
-mtr_t::release_block_at_savepoint(
- ulint savepoint,
- buf_block_t* block)
-{
- ut_ad(is_active());
-
- mtr_memo_slot_t *slot = m_memo.at<mtr_memo_slot_t*>(savepoint);
-
- ut_a(slot->object == block);
- slot->object= nullptr;
- block->page.unfix();
-
- switch (slot->type) {
- case MTR_MEMO_PAGE_S_FIX:
- block->page.lock.s_unlock();
- break;
- case MTR_MEMO_PAGE_SX_FIX:
- case MTR_MEMO_PAGE_X_FIX:
- block->page.lock.u_or_x_unlock(slot->type == MTR_MEMO_PAGE_SX_FIX);
- break;
- default:
- break;
- }
-}
diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
index 80542299482..28aa30565e4 100644
--- a/storage/innobase/include/page0cur.h
+++ b/storage/innobase/include/page0cur.h
@@ -129,7 +129,6 @@ page_cur_tuple_insert(
/*==================*/
page_cur_t* cursor, /*!< in/out: a page cursor */
const dtuple_t* tuple, /*!< in: pointer to a data tuple */
- dict_index_t* index, /*!< in: record descriptor */
rec_offs** offsets,/*!< out: offsets on *rec */
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
ulint n_ext, /*!< in: number of externally stored columns */
@@ -143,7 +142,6 @@ rec_t*
page_cur_insert_rec_low(
/*====================*/
const page_cur_t*cur, /*!< in: page cursor */
- dict_index_t* index, /*!< in: record descriptor */
const rec_t* rec, /*!< in: record to insert after cur */
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
mtr_t* mtr) /*!< in/out: mini-transaction */
@@ -165,7 +163,6 @@ page_cur_insert_rec_zip(
/*====================*/
page_cur_t* cursor, /*!< in/out: page cursor,
logical position unchanged */
- dict_index_t* index, /*!< in: record descriptor */
const rec_t* rec, /*!< in: pointer to a physical record */
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
mtr_t* mtr) /*!< in/out: mini-transaction */
@@ -177,7 +174,6 @@ void
page_cur_delete_rec(
/*================*/
page_cur_t* cursor, /*!< in/out: a page cursor */
- const dict_index_t* index, /*!< in: record descriptor */
const rec_offs* offsets,/*!< in: rec_get_offsets(
cursor->rec, index) */
mtr_t* mtr) /*!< in/out: mini-transaction */
@@ -239,8 +235,6 @@ Searches the right position for a page cursor. */
bool
page_cur_search_with_match(
/*=======================*/
- const buf_block_t* block, /*!< in: buffer block */
- const dict_index_t* index, /*!< in: record descriptor */
const dtuple_t* tuple, /*!< in: data tuple */
page_cur_mode_t mode, /*!< in: PAGE_CUR_L,
PAGE_CUR_LE, PAGE_CUR_G, or
@@ -251,13 +245,11 @@ page_cur_search_with_match(
ulint* ilow_matched_fields,
/*!< in/out: already matched
fields in lower limit record */
- page_cur_t* cursor, /*!< out: page cursor */
+ page_cur_t* cursor, /*!< in/out: page cursor */
rtr_info_t* rtr_info);/*!< in/out: rtree search stack */
#ifdef BTR_CUR_HASH_ADAPT
MY_ATTRIBUTE((warn_unused_result))
/** Search the right position for a page cursor.
-@param[in] block buffer block
-@param[in] index index tree
@param[in] tuple key to be searched for
@param[in] mode search mode
@param[in,out] iup_matched_fields already matched fields in the
@@ -268,11 +260,9 @@ first partially matched field in the upper limit record
lower limit record
@param[in,out] ilow_matched_bytes already matched bytes in the
first partially matched field in the lower limit record
-@param[out] cursor page cursor */
+@param[in,out] cursor page cursor */
bool
page_cur_search_with_match_bytes(
- const buf_block_t* block,
- const dict_index_t* index,
const dtuple_t* tuple,
page_cur_mode_t mode,
ulint* iup_matched_fields,
@@ -284,16 +274,12 @@ page_cur_search_with_match_bytes(
/***********************************************************//**
Positions a page cursor on a randomly chosen user record on a page. If there
are no user records, sets the cursor on the infimum record. */
-void
-page_cur_open_on_rnd_user_rec(
-/*==========================*/
- buf_block_t* block, /*!< in: page */
- page_cur_t* cursor);/*!< out: page cursor */
+void page_cur_open_on_rnd_user_rec(page_cur_t *cursor);
/** Index page cursor */
struct page_cur_t{
- const dict_index_t* index;
+ dict_index_t* index;
rec_t* rec; /*!< pointer to a record on page */
rec_offs* offsets;
buf_block_t* block; /*!< pointer to the block containing rec */
diff --git a/storage/innobase/include/page0cur.inl b/storage/innobase/include/page0cur.inl
index d6bf2fdfe09..7c4eafa266a 100644
--- a/storage/innobase/include/page0cur.inl
+++ b/storage/innobase/include/page0cur.inl
@@ -167,14 +167,12 @@ page_cur_tuple_insert(
/*==================*/
page_cur_t* cursor, /*!< in/out: a page cursor */
const dtuple_t* tuple, /*!< in: pointer to a data tuple */
- dict_index_t* index, /*!< in: record descriptor */
rec_offs** offsets,/*!< out: offsets on *rec */
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
ulint n_ext, /*!< in: number of externally stored columns */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
- rec_t* rec;
- ulint size = rec_get_converted_size(index, tuple, n_ext);
+ ulint size = rec_get_converted_size(cursor->index, tuple, n_ext);
if (!*heap) {
*heap = mem_heap_create(size
@@ -183,24 +181,23 @@ page_cur_tuple_insert(
* sizeof **offsets);
}
- rec = rec_convert_dtuple_to_rec((byte*) mem_heap_alloc(*heap, size),
- index, tuple, n_ext);
+ rec_t* rec = rec_convert_dtuple_to_rec(
+ static_cast<byte*>(mem_heap_alloc(*heap, size)),
+ cursor->index, tuple, n_ext);
- *offsets = rec_get_offsets(rec, index, *offsets,
+ *offsets = rec_get_offsets(rec, cursor->index, *offsets,
page_is_leaf(cursor->block->page.frame)
- ? index->n_core_fields : 0,
+ ? cursor->index->n_core_fields : 0,
ULINT_UNDEFINED, heap);
ut_ad(size == rec_offs_size(*offsets));
if (is_buf_block_get_page_zip(cursor->block)) {
- rec = page_cur_insert_rec_zip(
- cursor, index, rec, *offsets, mtr);
+ rec = page_cur_insert_rec_zip(cursor, rec, *offsets, mtr);
} else {
- rec = page_cur_insert_rec_low(cursor,
- index, rec, *offsets, mtr);
+ rec = page_cur_insert_rec_low(cursor, rec, *offsets, mtr);
}
- ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, index, *offsets));
+ ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, cursor->index, *offsets));
return(rec);
}
diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h
index 25c09258b3c..1f8af6030d1 100644
--- a/storage/innobase/include/row0ins.h
+++ b/storage/innobase/include/row0ins.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2021, MariaDB Corporation.
+Copyright (c) 2017, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -78,7 +78,7 @@ dberr_t
row_ins_clust_index_entry_low(
/*==========================*/
ulint flags, /*!< in: undo logging and locking flags */
- ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
depending on whether we wish optimistic or
pessimistic descent down the index tree */
dict_index_t* index, /*!< in: clustered index */
@@ -94,13 +94,13 @@ same fields is found, the other record is necessarily marked deleted.
It is then unmarked. Otherwise, the entry is just inserted to the index.
@retval DB_SUCCESS on success
@retval DB_LOCK_WAIT on lock wait when !(flags & BTR_NO_LOCKING_FLAG)
-@retval DB_FAIL if retry with BTR_MODIFY_TREE is needed
+@retval DB_FAIL if retry with BTR_INSERT_TREE is needed
@return error code */
dberr_t
row_ins_sec_index_entry_low(
/*========================*/
ulint flags, /*!< in: undo logging and locking flags */
- ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_INSERT_TREE,
depending on whether we wish optimistic or
pessimistic descent down the index tree */
dict_index_t* index, /*!< in: secondary index */
diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h
index 1e0fdc65238..a1350740e2a 100644
--- a/storage/innobase/include/row0row.h
+++ b/storage/innobase/include/row0row.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2016, 2020, MariaDB Corporation.
+Copyright (c) 2016, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -303,13 +303,13 @@ row_build_row_ref_fast(
/***************************************************************//**
Searches the clustered index record for a row, if we have the row
reference.
-@return TRUE if found */
-ibool
+@return true if found */
+bool
row_search_on_row_ref(
/*==================*/
btr_pcur_t* pcur, /*!< out: persistent cursor, which must
be closed by the caller */
- ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */
const dict_table_t* table, /*!< in: table */
const dtuple_t* ref, /*!< in: row reference */
mtr_t* mtr) /*!< in/out: mtr */
@@ -321,7 +321,7 @@ on the secondary index record are preserved.
rec_t*
row_get_clust_rec(
/*==============*/
- ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */
const rec_t* rec, /*!< in: record in a secondary index */
dict_index_t* index, /*!< in: secondary index */
dict_index_t** clust_index,/*!< out: clustered index */
@@ -363,9 +363,8 @@ Searches an index record.
enum row_search_result
row_search_index_entry(
/*===================*/
- dict_index_t* index, /*!< in: index */
const dtuple_t* entry, /*!< in: index entry */
- ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */
btr_pcur_t* pcur, /*!< in/out: persistent cursor, which must
be closed by the caller */
mtr_t* mtr) /*!< in: mtr */
diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc
index 60d661f95f1..5cd22257825 100644
--- a/storage/innobase/log/log0log.cc
+++ b/storage/innobase/log/log0log.cc
@@ -812,10 +812,14 @@ func_exit:
if (lsn <= sync_lsn)
{
+#ifndef DBUG_OFF
+ skip_checkpoint:
+#endif
log_sys.set_check_flush_or_checkpoint(false);
goto func_exit;
}
+ DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", goto skip_checkpoint;);
log_sys.latch.rd_unlock();
/* We must wait to prevent the tail of the log overwriting the head. */
@@ -912,13 +916,9 @@ loop:
}
/* We need these threads to stop early in shutdown. */
- const char* thread_name;
-
- if (srv_fast_shutdown != 2 && trx_rollback_is_active) {
- thread_name = "rollback of recovered transactions";
- } else {
- thread_name = NULL;
- }
+ const char* thread_name = srv_fast_shutdown != 2
+ && trx_rollback_is_active
+ ? "rollback of recovered transactions" : nullptr;
if (thread_name) {
ut_ad(!srv_read_only_mode);
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index a53bf30edf0..8da1fb9367e 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -1148,6 +1148,7 @@ public:
}
mtr.commit();
+ clear();
}
/** Clear the data structure */
@@ -1174,14 +1175,6 @@ inline void recv_sys_t::trim(const page_id_t page_id, lsn_t lsn)
pages.erase(r);
}
}
- if (fil_space_t* space = fil_space_get(page_id.space())) {
- ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
- fil_node_t* file = UT_LIST_GET_FIRST(space->chain);
- ut_ad(file->is_open());
- os_file_truncate(file->name, file->handle,
- os_offset_t{page_id.page_no()}
- << srv_page_size_shift, true);
- }
DBUG_VOID_RETURN;
}
@@ -3485,7 +3478,17 @@ void recv_sys_t::apply(bool last_batch)
{
const trunc& t= truncated_undo_spaces[id];
if (t.lsn)
- trim(page_id_t(id + srv_undo_space_id_start, t.pages), t.lsn);
+ {
+ trim(page_id_t(id + srv_undo_space_id_start, 0), t.lsn);
+ if (fil_space_t *space = fil_space_get(id + srv_undo_space_id_start))
+ {
+ ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
+ fil_node_t *file= UT_LIST_GET_FIRST(space->chain);
+ ut_ad(file->is_open());
+ os_file_truncate(file->name, file->handle,
+ os_offset_t{t.pages} << srv_page_size_shift, true);
+ }
+ }
}
fil_system.extend_to_recv_size();
diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc
index 52152d9a678..94d4971c9b6 100644
--- a/storage/innobase/mtr/mtr0mtr.cc
+++ b/storage/innobase/mtr/mtr0mtr.cc
@@ -32,181 +32,12 @@ Created 11/26/1995 Heikki Tuuri
#ifdef BTR_CUR_HASH_ADAPT
# include "btr0sea.h"
#endif
+#include "srv0start.h"
#include "log.h"
-/** Iterate over a memo block in reverse. */
-template <typename Functor>
-struct CIterate {
- CIterate() : functor() {}
-
- CIterate(const Functor& functor) : functor(functor) {}
-
- /** @return false if the functor returns false. */
- bool operator()(mtr_buf_t::block_t* block) const
- {
- const mtr_memo_slot_t* start =
- reinterpret_cast<const mtr_memo_slot_t*>(
- block->begin());
-
- mtr_memo_slot_t* slot =
- reinterpret_cast<mtr_memo_slot_t*>(
- block->end());
-
- ut_ad(!(block->used() % sizeof(*slot)));
-
- while (slot-- != start) {
-
- if (!functor(slot)) {
- return(false);
- }
- }
-
- return(true);
- }
-
- Functor functor;
-};
-
-template <typename Functor>
-struct Iterate {
- Iterate() : functor() {}
-
- Iterate(const Functor& functor) : functor(functor) {}
-
- /** @return false if the functor returns false. */
- bool operator()(mtr_buf_t::block_t* block)
- {
- const mtr_memo_slot_t* start =
- reinterpret_cast<const mtr_memo_slot_t*>(
- block->begin());
-
- mtr_memo_slot_t* slot =
- reinterpret_cast<mtr_memo_slot_t*>(
- block->end());
-
- ut_ad(!(block->used() % sizeof(*slot)));
-
- while (slot-- != start) {
-
- if (!functor(slot)) {
- return(false);
- }
- }
-
- return(true);
- }
-
- Functor functor;
-};
-
-/** Find specific object */
-struct Find {
-
- /** Constructor */
- Find(const void* object, ulint type)
- :
- m_slot(),
- m_type(type),
- m_object(object)
- {
- ut_a(object != NULL);
- }
-
- /** @return false if the object was found. */
- bool operator()(mtr_memo_slot_t* slot)
- {
- if (m_object == slot->object && m_type == slot->type) {
- m_slot = slot;
- return(false);
- }
-
- return(true);
- }
-
- /** Slot if found */
- mtr_memo_slot_t*m_slot;
-
- /** Type of the object to look for */
- const ulint m_type;
-
- /** The object instance to look for */
- const void* m_object;
-};
-
-/** Find a page frame */
-struct FindPage
+void mtr_memo_slot_t::release() const
{
- /** Constructor
- @param[in] ptr pointer to within a page frame
- @param[in] flags MTR_MEMO flags to look for */
- FindPage(const void* ptr, ulint flags)
- : m_ptr(ptr), m_flags(flags), m_slot(NULL)
- {
- /* There must be some flags to look for. */
- ut_ad(flags);
- /* We can only look for page-related flags. */
- ut_ad(!(flags & ulint(~(MTR_MEMO_PAGE_S_FIX
- | MTR_MEMO_PAGE_X_FIX
- | MTR_MEMO_PAGE_SX_FIX
- | MTR_MEMO_BUF_FIX
- | MTR_MEMO_MODIFY))));
- }
-
- /** Visit a memo entry.
- @param[in] slot memo entry to visit
- @retval false if a page was found
- @retval true if the iteration should continue */
- bool operator()(mtr_memo_slot_t* slot)
- {
- ut_ad(m_slot == NULL);
-
- if (!(m_flags & slot->type) || slot->object == NULL) {
- return(true);
- }
-
- buf_page_t* bpage = static_cast<buf_page_t*>(slot->object);
-
- if (m_ptr < bpage->frame
- || m_ptr >= bpage->frame + srv_page_size) {
- return(true);
- }
- ut_ad(!(slot->type & MTR_MEMO_PAGE_S_FIX)
- || bpage->lock.have_s());
- ut_ad(!(slot->type & MTR_MEMO_PAGE_SX_FIX)
- || bpage->lock.have_u_or_x());
- ut_ad(!(slot->type & MTR_MEMO_PAGE_X_FIX)
- || bpage->lock.have_x());
- m_slot = slot;
- return(false);
- }
-
- /** @return the slot that was found */
- mtr_memo_slot_t* get_slot() const
- {
- ut_ad(m_slot != NULL);
- return(m_slot);
- }
- /** @return the block that was found */
- buf_block_t* get_block() const
- {
- return(reinterpret_cast<buf_block_t*>(get_slot()->object));
- }
-private:
- /** Pointer inside a page frame to look for */
- const void*const m_ptr;
- /** MTR_MEMO flags to look for */
- const ulint m_flags;
- /** The slot corresponding to m_ptr */
- mtr_memo_slot_t* m_slot;
-};
-
-/** Release latches and decrement the buffer fix count.
-@param slot memo slot */
-static void memo_slot_release(mtr_memo_slot_t *slot)
-{
- void *object= slot->object;
- slot->object= nullptr;
- switch (const auto type= slot->type) {
+ switch (type) {
case MTR_MEMO_S_LOCK:
static_cast<index_lock*>(object)->s_unlock();
break;
@@ -224,7 +55,9 @@ static void memo_slot_release(mtr_memo_slot_t *slot)
break;
default:
buf_page_t *bpage= static_cast<buf_page_t*>(object);
- bpage->unfix();
+ ut_d(const auto s=)
+ bpage->unfix();
+ ut_ad(s < buf_page_t::READ_FIX || s >= buf_page_t::WRITE_FIX);
switch (type) {
case MTR_MEMO_PAGE_S_FIX:
bpage->lock.s_unlock();
@@ -241,118 +74,6 @@ static void memo_slot_release(mtr_memo_slot_t *slot)
}
}
-/** Release the latches acquired by the mini-transaction. */
-struct ReleaseLatches {
- /** @return true always. */
- bool operator()(mtr_memo_slot_t *slot) const
- {
- void *object= slot->object;
- if (!object)
- return true;
- slot->object= nullptr;
- switch (const auto type= slot->type) {
- case MTR_MEMO_S_LOCK:
- static_cast<index_lock*>(object)->s_unlock();
- break;
- case MTR_MEMO_SPACE_X_LOCK:
- static_cast<fil_space_t*>(object)->set_committed_size();
- static_cast<fil_space_t*>(object)->x_unlock();
- break;
- case MTR_MEMO_SPACE_S_LOCK:
- static_cast<fil_space_t*>(object)->s_unlock();
- break;
- case MTR_MEMO_X_LOCK:
- case MTR_MEMO_SX_LOCK:
- static_cast<index_lock*>(object)->
- u_or_x_unlock(type == MTR_MEMO_SX_LOCK);
- break;
- default:
- buf_page_t *bpage= static_cast<buf_page_t*>(object);
- bpage->unfix();
- switch (auto latch= slot->type & ~MTR_MEMO_MODIFY) {
- case MTR_MEMO_PAGE_S_FIX:
- bpage->lock.s_unlock();
- return true;
- case MTR_MEMO_PAGE_SX_FIX:
- case MTR_MEMO_PAGE_X_FIX:
- bpage->lock.u_or_x_unlock(latch == MTR_MEMO_PAGE_SX_FIX);
- /* fall through */
- case MTR_MEMO_BUF_FIX:
- return true;
- }
- ut_ad("invalid type" == 0);
- }
- return true;
- }
-};
-
-/** Release the latches and blocks acquired by the mini-transaction. */
-struct ReleaseAll {
- /** @return true always. */
- bool operator()(mtr_memo_slot_t *slot) const
- {
- if (slot->object)
- memo_slot_release(slot);
- return true;
- }
-};
-
-/** Stops iteration is savepoint is reached */
-template <typename Functor> struct TillSavepoint
-{
-
- /** Constructor
- @param[in] functor functor which is called if savepoint is not reached
- @param[in] savepoint savepoint value to rollback
- @param[in] used current position in slots container */
- TillSavepoint(const Functor &functor, ulint savepoint, ulint used)
- : functor(functor),
- m_slots_count((used - savepoint) / sizeof(mtr_memo_slot_t))
- {
- ut_ad(savepoint);
- ut_ad(used >= savepoint);
- }
-
- /** @return true if savepoint is not reached, false otherwise */
- bool operator()(mtr_memo_slot_t *slot)
- {
-#ifdef UNIV_DEBUG
- /** This check is added because the code is invoked only from
- row_search_mvcc() to release latches acquired during clustered index search
- for secondary index record. To make it more universal we could add one more
- member in this functor for debug build to pass only certain slot types,
- but this is currently not necessary. */
- switch (slot->type)
- {
- case MTR_MEMO_S_LOCK:
- case MTR_MEMO_PAGE_S_FIX:
- break;
- default:
- ut_a(false);
- }
-#endif
- return m_slots_count-- && functor(slot);
- }
-
-private:
- /** functor to invoke */
- const Functor &functor;
- /** slots count left till savepoint */
- ulint m_slots_count;
-};
-
-#ifdef UNIV_DEBUG
-/** Check that all slots have been handled. */
-struct DebugCheck {
- /** @return true always. */
- bool operator()(const mtr_memo_slot_t* slot) const
- {
- ut_ad(!slot->object);
- return(true);
- }
-};
-#endif
-
/** Prepare to insert a modified blcok into flush_list.
@param lsn start LSN of the mini-transaction
@return insert position for insert_into_flush_list() */
@@ -432,197 +153,14 @@ inline void buf_pool_t::insert_into_flush_list(buf_page_t *prev,
block->page.set_oldest_modification(lsn);
}
-/** Update modified pages of the mini-transaction. */
-struct ReleaseModified
-{
- buf_page_t *const prev;
- const lsn_t start, end;
- mutable size_t modified= 0;
-
- ReleaseModified(buf_page_t *prev, lsn_t start, lsn_t end) :
- prev(prev), start(start), end(end)
- {
- ut_ad(start > 2);
- ut_ad(end >= start);
- }
-
- /** @return true always */
- bool operator()(mtr_memo_slot_t *slot) const
- {
- if (!slot->object || !(slot->type & MTR_MEMO_MODIFY))
- return true;
- ut_ad(slot->type == MTR_MEMO_PAGE_X_MODIFY ||
- slot->type == MTR_MEMO_PAGE_SX_MODIFY);
-
- modified++;
- buf_block_t *b= static_cast<buf_block_t*>(slot->object);
- ut_ad(b->page.id() < end_page_id);
- ut_d(const auto s= b->page.state());
- ut_ad(s > buf_page_t::FREED);
- ut_ad(s < buf_page_t::READ_FIX);
- ut_ad(mach_read_from_8(b->page.frame + FIL_PAGE_LSN) <= end);
- mach_write_to_8(b->page.frame + FIL_PAGE_LSN, end);
- if (UNIV_LIKELY_NULL(b->page.zip.data))
- memcpy_aligned<8>(FIL_PAGE_LSN + b->page.zip.data,
- FIL_PAGE_LSN + b->page.frame, 8);
- buf_pool.insert_into_flush_list(prev, b, start);
- return true;
- }
-};
-
-/** Release latches to already dirtied pages.
-This is a bit more than ReleaseAll,
-kind of a combination of ReleaseLatches and a subset of ReleaseModified. */
-struct ReleaseSimple
-{
- const lsn_t end;
- mutable size_t modified;
- ReleaseSimple(lsn_t end) : end(end), modified(0) { ut_ad(end); }
-
- /** @return true always */
- bool operator()(mtr_memo_slot_t *slot) const
- {
- void *object= slot->object;
- if (!object)
- return true;
- slot->object= nullptr;
- switch (const auto type= slot->type) {
- case MTR_MEMO_S_LOCK:
- static_cast<index_lock*>(object)->s_unlock();
- break;
- case MTR_MEMO_SPACE_X_LOCK:
- static_cast<fil_space_t*>(object)->set_committed_size();
- static_cast<fil_space_t*>(object)->x_unlock();
- break;
- case MTR_MEMO_SPACE_S_LOCK:
- static_cast<fil_space_t*>(object)->s_unlock();
- break;
- case MTR_MEMO_X_LOCK:
- case MTR_MEMO_SX_LOCK:
- static_cast<index_lock*>(object)->
- u_or_x_unlock(type == MTR_MEMO_SX_LOCK);
- break;
- default:
- buf_page_t *bpage= static_cast<buf_page_t*>(object);
- if (type & MTR_MEMO_MODIFY)
- {
- ut_ad(slot->type == MTR_MEMO_PAGE_X_MODIFY ||
- slot->type == MTR_MEMO_PAGE_SX_MODIFY);
- ut_ad(bpage->oldest_modification() > 1);
- ut_ad(bpage->oldest_modification() < end);
- ut_ad(bpage->id() < end_page_id);
- ut_d(const auto s= bpage->state());
- ut_ad(s > buf_page_t::FREED);
- ut_ad(s < buf_page_t::READ_FIX);
- ut_ad(mach_read_from_8(bpage->frame + FIL_PAGE_LSN) <= end);
- mach_write_to_8(bpage->frame + FIL_PAGE_LSN, end);
- if (UNIV_LIKELY_NULL(bpage->zip.data))
- memcpy_aligned<8>(FIL_PAGE_LSN + bpage->zip.data,
- FIL_PAGE_LSN + bpage->frame, 8);
- modified++;
- }
- bpage->unfix();
- switch (auto latch= type & ~MTR_MEMO_MODIFY) {
- case MTR_MEMO_PAGE_S_FIX:
- bpage->lock.s_unlock();
- return true;
- case MTR_MEMO_PAGE_SX_FIX:
- case MTR_MEMO_PAGE_X_FIX:
- bpage->lock.u_or_x_unlock(latch == MTR_MEMO_PAGE_SX_FIX);
- /* fall through */
- case MTR_MEMO_BUF_FIX:
- return true;
- }
- ut_ad("invalid type" == 0);
- }
- return true;
- }
-};
-
-ATTRIBUTE_COLD __attribute__((noinline))
-/** Insert a modified block into buf_pool.flush_list on IMPORT TABLESPACE. */
-static void insert_imported(buf_block_t *block)
-{
- ut_d(const auto s= block->page.state());
- ut_ad(s > buf_page_t::FREED);
- ut_ad(s < buf_page_t::READ_FIX);
- if (block->page.oldest_modification() <= 1)
- {
- log_sys.latch.rd_lock(SRW_LOCK_CALL);
- const lsn_t lsn= log_sys.last_checkpoint_lsn;
- mysql_mutex_lock(&buf_pool.flush_list_mutex);
- buf_pool.insert_into_flush_list
- (buf_pool.prepare_insert_into_flush_list(lsn), block, lsn);
- log_sys.latch.rd_unlock();
- mysql_mutex_unlock(&buf_pool.flush_list_mutex);
- }
-}
-
-/** Release latches to already pages when no log was written.
-This is like ReleaseSimple, but it cover pages of the temporary tablespace
-as well as pages modified during IMPORT TABLESPACE. */
-struct ReleaseUnlogged
-{
- /** @return true always */
- bool operator()(mtr_memo_slot_t *slot) const
- {
- void *object= slot->object;
- if (!object)
- return true;
- slot->object= nullptr;
- switch (const auto type= slot->type) {
- case MTR_MEMO_S_LOCK:
- static_cast<index_lock*>(object)->s_unlock();
- break;
- case MTR_MEMO_SPACE_X_LOCK:
- static_cast<fil_space_t*>(object)->set_committed_size();
- static_cast<fil_space_t*>(object)->x_unlock();
- break;
- case MTR_MEMO_SPACE_S_LOCK:
- static_cast<fil_space_t*>(object)->s_unlock();
- break;
- case MTR_MEMO_X_LOCK:
- case MTR_MEMO_SX_LOCK:
- static_cast<index_lock*>(object)->
- u_or_x_unlock(type == MTR_MEMO_SX_LOCK);
- break;
- default:
- buf_block_t *block= static_cast<buf_block_t*>(object);
- block->page.unfix();
-
- if (type & MTR_MEMO_MODIFY)
- {
- ut_ad(type == MTR_MEMO_PAGE_X_MODIFY ||
- type == MTR_MEMO_PAGE_SX_MODIFY);
- if (UNIV_LIKELY(block->page.id() >= end_page_id))
- block->page.set_temp_modified();
- else
- insert_imported(block);
- }
-
- switch (type) {
- case MTR_MEMO_PAGE_S_FIX:
- block->page.lock.s_unlock();
- break;
- case MTR_MEMO_BUF_FIX:
- break;
- default:
- ut_ad(type == MTR_MEMO_PAGE_SX_FIX || type == MTR_MEMO_PAGE_X_FIX ||
- type == MTR_MEMO_PAGE_SX_MODIFY ||
- type == MTR_MEMO_PAGE_X_MODIFY);
- block->page.lock.u_or_x_unlock(type & MTR_MEMO_PAGE_SX_FIX);
- }
- }
- return true;
- }
-};
-
/** Start a mini-transaction. */
void mtr_t::start()
{
+ ut_ad(!m_memo);
ut_ad(!m_freed_pages);
ut_ad(!m_freed_space);
MEM_UNDEFINED(this, sizeof *this);
+ MEM_MAKE_DEFINED(&m_memo, sizeof m_memo);
MEM_MAKE_DEFINED(&m_freed_space, sizeof m_freed_space);
MEM_MAKE_DEFINED(&m_freed_pages, sizeof m_freed_pages);
@@ -633,7 +171,6 @@ void mtr_t::start()
m_last= nullptr;
m_last_offset= 0;
- new(&m_memo) mtr_buf_t();
new(&m_log) mtr_buf_t();
m_made_dirty= false;
@@ -651,9 +188,8 @@ void mtr_t::start()
inline void mtr_t::release_resources()
{
ut_ad(is_active());
- ut_d(m_memo.for_each_block_in_reverse(CIterate<DebugCheck>()));
+ ut_ad(!m_memo);
m_log.erase();
- m_memo.erase();
ut_d(m_commit= true);
}
@@ -686,13 +222,101 @@ void mtr_t::process_freed_pages()
ut_ad(!m_freed_space);
}
+ATTRIBUTE_COLD __attribute__((noinline))
+/** Insert a modified block into buf_pool.flush_list on IMPORT TABLESPACE. */
+static void insert_imported(buf_block_t *block)
+{
+ if (block->page.oldest_modification() <= 1)
+ {
+ log_sys.latch.rd_lock(SRW_LOCK_CALL);
+ const lsn_t lsn= log_sys.last_checkpoint_lsn;
+ mysql_mutex_lock(&buf_pool.flush_list_mutex);
+ buf_pool.insert_into_flush_list
+ (buf_pool.prepare_insert_into_flush_list(lsn), block, lsn);
+ log_sys.latch.rd_unlock();
+ mysql_mutex_unlock(&buf_pool.flush_list_mutex);
+ }
+}
+
/** Release modified pages when no log was written. */
void mtr_t::release_unlogged()
{
ut_ad(m_log_mode == MTR_LOG_NO_REDO);
ut_ad(m_log.size() == 0);
+ ut_ad(m_memo);
+
process_freed_pages();
- m_memo.for_each_block_in_reverse(CIterate<ReleaseUnlogged>());
+
+ for (auto it= m_memo->rbegin(); it != m_memo->rend(); it++)
+ {
+ mtr_memo_slot_t &slot= *it;
+ if (!slot.object)
+ continue;
+ switch (slot.type) {
+ case MTR_MEMO_S_LOCK:
+ static_cast<index_lock*>(slot.object)->s_unlock();
+ break;
+ case MTR_MEMO_SPACE_X_LOCK:
+ static_cast<fil_space_t*>(slot.object)->set_committed_size();
+ static_cast<fil_space_t*>(slot.object)->x_unlock();
+ break;
+ case MTR_MEMO_SPACE_S_LOCK:
+ static_cast<fil_space_t*>(slot.object)->s_unlock();
+ break;
+ case MTR_MEMO_X_LOCK:
+ case MTR_MEMO_SX_LOCK:
+ static_cast<index_lock*>(slot.object)->
+ u_or_x_unlock(slot.type == MTR_MEMO_SX_LOCK);
+ break;
+ default:
+ buf_block_t *block= static_cast<buf_block_t*>(slot.object);
+ ut_d(const auto s=) block->page.unfix();
+ ut_ad(s >= buf_page_t::FREED);
+ ut_ad(s < buf_page_t::READ_FIX);
+
+ if (slot.type & MTR_MEMO_MODIFY)
+ {
+ ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
+ slot.type == MTR_MEMO_PAGE_SX_MODIFY);
+ if (UNIV_LIKELY(block->page.id() >= end_page_id))
+ block->page.set_temp_modified();
+ else
+ insert_imported(block);
+ }
+
+ switch (slot.type) {
+ case MTR_MEMO_PAGE_S_FIX:
+ block->page.lock.s_unlock();
+ break;
+ case MTR_MEMO_BUF_FIX:
+ break;
+ default:
+ ut_ad(slot.type == MTR_MEMO_PAGE_SX_FIX ||
+ slot.type == MTR_MEMO_PAGE_X_FIX ||
+ slot.type == MTR_MEMO_PAGE_SX_MODIFY ||
+ slot.type == MTR_MEMO_PAGE_X_MODIFY);
+ block->page.lock.u_or_x_unlock(slot.type & MTR_MEMO_PAGE_SX_FIX);
+ }
+ }
+ }
+
+ delete m_memo;
+ m_memo= nullptr;
+}
+
+void mtr_t::release()
+{
+ if (m_memo)
+ {
+ for (auto it= m_memo->rbegin(); it != m_memo->rend(); it++)
+ {
+ mtr_memo_slot_t &slot= *it;
+ if (slot.object)
+ slot.release();
+ }
+ delete m_memo;
+ m_memo= nullptr;
+ }
}
/** Commit a mini-transaction. */
@@ -720,16 +344,40 @@ void mtr_t::commit()
if (m_made_dirty)
{
+ ut_ad(m_memo);
+ size_t modified= 0;
+ auto it= m_memo->rbegin();
+
mysql_mutex_lock(&buf_pool.flush_list_mutex);
+
+ buf_page_t *const prev=
+ buf_pool.prepare_insert_into_flush_list(lsns.first);
+
+ while (it != m_memo->rend())
{
- CIterate<ReleaseModified> rm
- {ReleaseModified{buf_pool.prepare_insert_into_flush_list(lsns.first),
- lsns.first, m_commit_lsn}};
- m_memo.for_each_block_in_reverse(rm);
- ut_ad(rm.functor.modified);
- buf_pool.flush_list_requests+= rm.functor.modified;
+ const mtr_memo_slot_t &slot= *it++;
+ if (slot.object && slot.type & MTR_MEMO_MODIFY)
+ {
+ ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
+ slot.type == MTR_MEMO_PAGE_SX_MODIFY);
+ modified++;
+ buf_block_t *b= static_cast<buf_block_t*>(slot.object);
+ ut_ad(b->page.id() < end_page_id);
+ ut_d(const auto s= b->page.state());
+ ut_ad(s > buf_page_t::FREED);
+ ut_ad(s < buf_page_t::READ_FIX);
+ ut_ad(mach_read_from_8(b->page.frame + FIL_PAGE_LSN) <=
+ m_commit_lsn);
+ mach_write_to_8(b->page.frame + FIL_PAGE_LSN, m_commit_lsn);
+ if (UNIV_LIKELY_NULL(b->page.zip.data))
+ memcpy_aligned<8>(FIL_PAGE_LSN + b->page.zip.data,
+ FIL_PAGE_LSN + b->page.frame, 8);
+ buf_pool.insert_into_flush_list(prev, b, lsns.first);
+ }
}
+ ut_ad(modified);
+ buf_pool.flush_list_requests+= modified;
buf_pool.page_cleaner_wakeup();
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
@@ -741,7 +389,7 @@ void mtr_t::commit()
else
log_sys.latch.rd_unlock();
- m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>());
+ release();
}
else
{
@@ -752,82 +400,106 @@ void mtr_t::commit()
}
else
log_sys.latch.rd_unlock();
- Iterate<ReleaseSimple> rs{ReleaseSimple{m_commit_lsn}};
- m_memo.for_each_block_in_reverse(rs);
- buf_pool.add_flush_list_requests(rs.functor.modified);
+
+ if (m_memo)
+ {
+ size_t modified= 0;
+
+ for (auto it= m_memo->rbegin(); it != m_memo->rend(); )
+ {
+ const mtr_memo_slot_t &slot= *it++;
+ if (!slot.object)
+ continue;
+ switch (slot.type) {
+ case MTR_MEMO_S_LOCK:
+ static_cast<index_lock*>(slot.object)->s_unlock();
+ break;
+ case MTR_MEMO_SPACE_X_LOCK:
+ static_cast<fil_space_t*>(slot.object)->set_committed_size();
+ static_cast<fil_space_t*>(slot.object)->x_unlock();
+ break;
+ case MTR_MEMO_SPACE_S_LOCK:
+ static_cast<fil_space_t*>(slot.object)->s_unlock();
+ break;
+ case MTR_MEMO_X_LOCK:
+ case MTR_MEMO_SX_LOCK:
+ static_cast<index_lock*>(slot.object)->
+ u_or_x_unlock(slot.type == MTR_MEMO_SX_LOCK);
+ break;
+ default:
+ buf_page_t *bpage= static_cast<buf_page_t*>(slot.object);
+ const auto s= bpage->unfix();
+ if (slot.type & MTR_MEMO_MODIFY)
+ {
+ ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
+ slot.type == MTR_MEMO_PAGE_SX_MODIFY);
+ ut_ad(bpage->oldest_modification() > 1);
+ ut_ad(bpage->oldest_modification() < m_commit_lsn);
+ ut_ad(bpage->id() < end_page_id);
+ ut_ad(s >= buf_page_t::FREED);
+ ut_ad(s < buf_page_t::READ_FIX);
+ ut_ad(mach_read_from_8(bpage->frame + FIL_PAGE_LSN) <=
+ m_commit_lsn);
+ if (s >= buf_page_t::UNFIXED)
+ {
+ mach_write_to_8(bpage->frame + FIL_PAGE_LSN, m_commit_lsn);
+ if (UNIV_LIKELY_NULL(bpage->zip.data))
+ memcpy_aligned<8>(FIL_PAGE_LSN + bpage->zip.data,
+ FIL_PAGE_LSN + bpage->frame, 8);
+ }
+ modified++;
+ }
+ switch (auto latch= slot.type & ~MTR_MEMO_MODIFY) {
+ case MTR_MEMO_PAGE_S_FIX:
+ bpage->lock.s_unlock();
+ continue;
+ case MTR_MEMO_PAGE_SX_FIX:
+ case MTR_MEMO_PAGE_X_FIX:
+ bpage->lock.u_or_x_unlock(latch == MTR_MEMO_PAGE_SX_FIX);
+ continue;
+ default:
+ ut_ad(latch == MTR_MEMO_BUF_FIX);
+ }
+ }
+ }
+
+ buf_pool.add_flush_list_requests(modified);
+ delete m_memo;
+ m_memo= nullptr;
+ }
}
if (UNIV_UNLIKELY(lsns.second != PAGE_FLUSH_NO))
buf_flush_ahead(m_commit_lsn, lsns.second == PAGE_FLUSH_SYNC);
}
else
- m_memo.for_each_block_in_reverse(CIterate<ReleaseAll>());
+ release();
func_exit:
release_resources();
}
-/** Release latches till savepoint. To simplify the code only
-MTR_MEMO_S_LOCK and MTR_MEMO_PAGE_S_FIX slot types are allowed to be
-released, otherwise it would be neccesary to add one more argument in the
-function to point out what slot types are allowed for rollback, and this
-would be overengineering as corrently the function is used only in one place
-in the code.
-@param savepoint savepoint, can be obtained with get_savepoint */
-void mtr_t::rollback_to_savepoint(ulint savepoint)
-{
- Iterate<TillSavepoint<ReleaseLatches>> iteration(
- TillSavepoint<ReleaseLatches>(ReleaseLatches(), savepoint,
- get_savepoint()));
- m_memo.for_each_block_in_reverse(iteration);
-}
-
-/** Shrink a tablespace. */
-struct Shrink
+void mtr_t::rollback_to_savepoint(ulint begin, ulint end)
{
- /** the first non-existing page in the tablespace */
- const page_id_t high;
-
- Shrink(const fil_space_t &space) : high({space.id, space.size}) {}
+ ut_ad(m_memo);
+ ut_ad(end <= m_memo->size());
+ ut_ad(begin <= end);
+ ulint s= end;
- bool operator()(mtr_memo_slot_t *slot) const
+ while (s-- > begin)
{
- if (!slot->object)
- return true;
- switch (slot->type) {
- default:
- ut_ad("invalid type" == 0);
- return false;
- case MTR_MEMO_SPACE_X_LOCK:
- ut_ad(high.space() == static_cast<fil_space_t*>(slot->object)->id);
- return true;
- case MTR_MEMO_PAGE_X_MODIFY:
- case MTR_MEMO_PAGE_SX_MODIFY:
- case MTR_MEMO_PAGE_X_FIX:
- case MTR_MEMO_PAGE_SX_FIX:
- auto &bpage= static_cast<buf_block_t*>(slot->object)->page;
- const auto s= bpage.state();
- ut_ad(s >= buf_page_t::FREED);
- ut_ad(s < buf_page_t::READ_FIX);
- ut_ad(bpage.frame);
- const page_id_t id{bpage.id()};
- if (id < high)
- {
- ut_ad(id.space() == high.space() ||
- (id == page_id_t{0, TRX_SYS_PAGE_NO} &&
- srv_is_undo_tablespace(high.space())));
- break;
- }
- if (s >= buf_page_t::UNFIXED)
- bpage.set_freed(s);
- ut_ad(id.space() == high.space());
- if (bpage.oldest_modification() > 1)
- bpage.reset_oldest_modification();
- slot->type= static_cast<mtr_memo_type_t>(slot->type & ~MTR_MEMO_MODIFY);
- }
- return true;
+ const mtr_memo_slot_t &slot= (*m_memo)[s];
+ if (!slot.object)
+ continue;
+ /* This is intended for releasing latches on indexes or unmodified
+ buffer pool pages. */
+ ut_ad(slot.type <= MTR_MEMO_SX_LOCK);
+ ut_ad(!(slot.type & MTR_MEMO_MODIFY));
+ slot.release();
}
-};
+
+ m_memo->erase(m_memo->begin() + begin, m_memo->begin() + end);
+}
/** Commit a mini-transaction that is shrinking a tablespace.
@param space tablespace that is being shrunk */
@@ -838,6 +510,7 @@ void mtr_t::commit_shrink(fil_space_t &space)
ut_ad(!high_level_read_only);
ut_ad(m_modifications);
ut_ad(m_made_dirty);
+ ut_ad(m_memo);
ut_ad(!recv_recovery_is_on());
ut_ad(m_log_mode == MTR_LOG_ALL);
ut_ad(UT_LIST_GET_LEN(space.chain) == 1);
@@ -861,18 +534,64 @@ void mtr_t::commit_shrink(fil_space_t &space)
ut_ad(!m_freed_pages || m_freed_space == &space);
process_freed_pages();
- m_memo.for_each_block_in_reverse(CIterate<Shrink>{space});
+ const page_id_t high{space.id, space.size};
+ size_t modified= 0;
+ auto it= m_memo->rbegin();
mysql_mutex_lock(&buf_pool.flush_list_mutex);
+
+ buf_page_t *const prev= buf_pool.prepare_insert_into_flush_list(start_lsn);
+
+ while (it != m_memo->rend())
{
- CIterate<ReleaseModified> rm
- {ReleaseModified{buf_pool.prepare_insert_into_flush_list(start_lsn),
- start_lsn, m_commit_lsn}};
- m_memo.for_each_block_in_reverse(rm);
- ut_ad(rm.functor.modified);
- buf_pool.flush_list_requests+= rm.functor.modified;
+ mtr_memo_slot_t &slot= *it++;
+
+ if (!slot.object);
+ else if (slot.type == MTR_MEMO_SPACE_X_LOCK)
+ ut_ad(high.space() == static_cast<fil_space_t*>(slot.object)->id);
+ else
+ {
+ ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
+ slot.type == MTR_MEMO_PAGE_SX_MODIFY ||
+ slot.type == MTR_MEMO_PAGE_X_FIX ||
+ slot.type == MTR_MEMO_PAGE_SX_FIX);
+ buf_block_t *b= static_cast<buf_block_t*>(slot.object);
+ const page_id_t id{b->page.id()};
+ const auto s= b->page.state();
+ ut_ad(s > buf_page_t::FREED);
+ ut_ad(s < buf_page_t::READ_FIX);
+ ut_ad(b->page.frame);
+ ut_ad(mach_read_from_8(b->page.frame + FIL_PAGE_LSN) <= m_commit_lsn);
+ ut_ad(!b->page.zip.data); // we no not shrink ROW_FORMAT=COMPRESSED
+
+ if (id < high)
+ {
+ ut_ad(id.space() == high.space() ||
+ (id == page_id_t{0, TRX_SYS_PAGE_NO} &&
+ srv_is_undo_tablespace(high.space())));
+ if (slot.type & MTR_MEMO_MODIFY)
+ {
+ modified++;
+ mach_write_to_8(b->page.frame + FIL_PAGE_LSN, m_commit_lsn);
+ buf_pool.insert_into_flush_list(prev, b, start_lsn);
+ }
+ }
+ else
+ {
+ ut_ad(id.space() == high.space());
+ if (s >= buf_page_t::UNFIXED)
+ b->page.set_freed(s);
+ if (b->page.oldest_modification() > 1)
+ b->page.reset_oldest_modification();
+ slot.type= mtr_memo_type_t(slot.type & ~MTR_MEMO_MODIFY);
+ }
+ }
}
+
+ ut_ad(modified);
+ buf_pool.flush_list_requests+= modified;
buf_pool.page_cleaner_wakeup();
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
+
log_sys.latch.wr_unlock();
m_latch_ex= false;
@@ -883,8 +602,7 @@ void mtr_t::commit_shrink(fil_space_t &space)
space.is_being_truncated= false;
mysql_mutex_unlock(&fil_system.mutex);
- m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>());
-
+ release();
release_resources();
}
@@ -988,7 +706,6 @@ bool mtr_t::commit_file(fil_space_t &space, const char *name)
}
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
- ut_d(m_log.erase());
release_resources();
return success;
@@ -1010,7 +727,7 @@ lsn_t mtr_t::commit_files(lsn_t checkpoint_lsn)
ut_ad(!is_inside_ibuf());
ut_ad(m_log_mode == MTR_LOG_ALL);
ut_ad(!m_made_dirty);
- ut_ad(m_memo.size() == 0);
+ ut_ad(!m_memo);
ut_ad(!srv_read_only_mode);
ut_ad(!m_freed_space);
ut_ad(!m_freed_pages);
@@ -1117,67 +834,48 @@ void mtr_t::x_lock_space(fil_space_t *space)
}
}
-/** Release an object in the memo stack.
-@return true if released */
-bool
-mtr_t::memo_release(const void* object, ulint type)
+void mtr_t::release(const void *object)
{
- ut_ad(is_active());
-
- /* We cannot release a page that has been written to in the
- middle of a mini-transaction. */
- ut_ad(!m_modifications || type != MTR_MEMO_PAGE_X_FIX);
-
- Iterate<Find> iteration(Find(object, type));
-
- if (!m_memo.for_each_block_in_reverse(iteration)) {
- memo_slot_release(iteration.functor.m_slot);
- return(true);
- }
-
- return(false);
-}
-
-/** Release a page latch.
-@param[in] ptr pointer to within a page frame
-@param[in] type object type: MTR_MEMO_PAGE_X_FIX, ... */
-void
-mtr_t::release_page(const void* ptr, mtr_memo_type_t type)
-{
- ut_ad(is_active());
-
- /* We cannot release a page that has been written to in the
- middle of a mini-transaction. */
- ut_ad(!m_modifications || type != MTR_MEMO_PAGE_X_FIX);
-
- Iterate<FindPage> iteration(FindPage(ptr, type));
-
- if (!m_memo.for_each_block_in_reverse(iteration)) {
- memo_slot_release(iteration.functor.get_slot());
- return;
- }
-
- /* The page was not found! */
- ut_ad(0);
+ ut_ad(is_active());
+ ut_ad(m_memo);
+
+ auto it=
+ std::find_if(m_memo->begin(), m_memo->end(),
+ [object](const mtr_memo_slot_t& slot)
+ { return slot.object == object; });
+ ut_ad(it != m_memo->end());
+ ut_ad(!(it->type & MTR_MEMO_MODIFY));
+ it->release();
+ m_memo->erase(it);
+ ut_ad(std::find_if(m_memo->begin(), m_memo->end(),
+ [object](const mtr_memo_slot_t& slot)
+ { return slot.object == &object; }) == m_memo->end());
}
-static bool log_close_warned;
static time_t log_close_warn_time;
/** Display a warning that the log tail is overwriting the head,
making the server crash-unsafe. */
-ATTRIBUTE_COLD static void log_overwrite_warning(lsn_t age, lsn_t capacity)
+ATTRIBUTE_COLD static void log_overwrite_warning(lsn_t lsn)
{
+ if (log_sys.overwrite_warned)
+ return;
+
time_t t= time(nullptr);
- if (!log_close_warned || difftime(t, log_close_warn_time) > 15)
- {
- log_close_warned= true;
- log_close_warn_time= t;
+ if (difftime(t, log_close_warn_time) < 15)
+ return;
- sql_print_error("InnoDB: The age of the last checkpoint is " LSN_PF
- ", which exceeds the log capacity " LSN_PF ".",
- age, capacity);
- }
+ if (!log_sys.overwrite_warned)
+ log_sys.overwrite_warned= lsn;
+ log_close_warn_time= t;
+
+ sql_print_error("InnoDB: Crash recovery is broken due to"
+ " insufficient innodb_log_file_size;"
+ " last checkpoint LSN=" LSN_PF ", current LSN=" LSN_PF
+ "%s.",
+ lsn_t{log_sys.last_checkpoint_lsn}, lsn,
+ srv_shutdown_state != SRV_SHUTDOWN_INITIATED
+ ? ". Shutdown is in progress" : "");
}
/** Wait in append_prepare() for buffer to become available
@@ -1265,7 +963,7 @@ static mtr_t::page_flush_ahead log_close(lsn_t lsn) noexcept
if (UNIV_UNLIKELY(checkpoint_age >= log_sys.log_capacity) &&
/* silence message on create_log_file() after the log had been deleted */
checkpoint_age != lsn)
- log_overwrite_warning(checkpoint_age, log_sys.log_capacity);
+ log_overwrite_warning(lsn);
else if (UNIV_LIKELY(checkpoint_age <= log_sys.max_modified_age_async))
return mtr_t::PAGE_FLUSH_NO;
else if (UNIV_LIKELY(checkpoint_age <= log_sys.max_checkpoint_age))
@@ -1318,50 +1016,36 @@ inline void mtr_t::page_checksum(const buf_page_t &bpage)
m_log.close(l + 4);
}
-/** Write OPT_PAGE_CHECKSUM records for modified pages */
-struct WriteOPT_PAGE_CHECKSUM
-{
- mtr_t &mtr;
- WriteOPT_PAGE_CHECKSUM(mtr_t &mtr) : mtr(mtr) {}
-
- /** @return true always */
- bool operator()(const mtr_memo_slot_t *slot) const
- {
- if (slot->type & MTR_MEMO_MODIFY)
- {
- const buf_page_t &b= static_cast<const buf_block_t*>(slot->object)->page;
- if (!b.is_freed())
- mtr.page_checksum(b);
- }
- return true;
- }
-};
-
std::pair<lsn_t,mtr_t::page_flush_ahead> mtr_t::do_write()
{
ut_ad(!recv_no_log_write);
ut_ad(is_logged());
+ ut_ad(m_log.size());
#ifndef SUX_LOCK_GENERIC
ut_ad(!m_latch_ex || log_sys.latch.is_write_locked());
#endif
- size_t len= m_log.size() + 5;
- ut_ad(len > 5);
-
#ifndef DBUG_OFF
- if (m_log_mode == MTR_LOG_ALL)
+ do
{
- m_memo.for_each_block(CIterate<WriteOPT_PAGE_CHECKSUM>(*this));
- do
- {
- DBUG_EXECUTE_IF("skip_page_checksum", continue;);
- m_memo.for_each_block(CIterate<WriteOPT_PAGE_CHECKSUM>(*this));
- len= m_log.size() + 5;
- }
- while (0);
+ if (!m_memo || m_log_mode != MTR_LOG_ALL)
+ continue;
+ DBUG_EXECUTE_IF("skip_page_checksum", continue;);
+
+ for (const mtr_memo_slot_t& slot : *m_memo)
+ if (slot.type & MTR_MEMO_MODIFY)
+ {
+ const buf_page_t &b= *static_cast<const buf_page_t*>(slot.object);
+ if (!b.is_freed())
+ page_checksum(b);
+ }
}
+ while (0);
#endif
+ size_t len= m_log.size() + 5;
+ ut_ad(len > 5);
+
if (log_sys.is_encrypted())
{
len+= 8;
@@ -1482,131 +1166,95 @@ mtr_t::finish_write(size_t len)
return {start.first, log_close(m_commit_lsn)};
}
-/** Find out whether a block was not X-latched by the mini-transaction */
-struct FindBlockX
-{
- const buf_block_t &block;
-
- FindBlockX(const buf_block_t &block): block(block) {}
-
- /** @return whether the block was not found x-latched */
- bool operator()(const mtr_memo_slot_t *slot) const
- {
- return slot->object != &block || !(slot->type & MTR_MEMO_PAGE_X_FIX);
- }
-};
-
-/** Find out whether a block was not X or U latched by the mini-transaction */
-struct FindBlockUX
+bool mtr_t::have_x_latch(const buf_block_t &block) const
{
- const buf_block_t &block;
+ if (!m_memo)
+ return false;
- FindBlockUX(const buf_block_t &block): block(block) {}
+ const mtr_memo_slot_t *found= nullptr;
- /** @return whether the block was not found x-latched */
- bool operator()(const mtr_memo_slot_t *slot) const
+ for (const mtr_memo_slot_t &slot : *m_memo)
{
- return slot->object != &block ||
- !(slot->type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
- }
-};
+ if (slot.object != &block)
+ continue;
-#ifdef UNIV_DEBUG
-/** Assert that the block is not present in the mini-transaction */
-struct FindNoBlock
-{
- const buf_block_t &block;
+ found= &slot;
- FindNoBlock(const buf_block_t &block): block(block) {}
+ if (!(slot.type & MTR_MEMO_PAGE_X_FIX))
+ continue;
- /** @return whether the block was not found */
- bool operator()(const mtr_memo_slot_t *slot) const
- {
- return slot->object != &block;
+ ut_ad(block.page.lock.have_x());
+ return true;
}
-};
-#endif /* UNIV_DEBUG */
-bool mtr_t::have_x_latch(const buf_block_t &block) const
-{
- if (m_memo.for_each_block(CIterate<FindBlockX>(FindBlockX(block))))
- {
- ut_ad(m_memo.for_each_block(CIterate<FindNoBlock>(FindNoBlock(block))));
- ut_ad(!memo_contains_flagged(&block,
- MTR_MEMO_PAGE_S_FIX | MTR_MEMO_PAGE_SX_FIX |
- MTR_MEMO_BUF_FIX | MTR_MEMO_MODIFY));
- return false;
- }
- ut_ad(block.page.lock.have_x());
- return true;
+ ut_ad(!found);
+ return false;
}
bool mtr_t::have_u_or_x_latch(const buf_block_t &block) const
{
- if (m_memo.for_each_block(CIterate<FindBlockUX>(FindBlockUX(block))))
- return false;
- ut_ad(block.page.lock.have_u_or_x());
- return true;
+ if (m_memo)
+ {
+ for (const mtr_memo_slot_t &slot : *m_memo)
+ {
+ if (slot.object == &block &&
+ slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))
+ {
+ ut_ad(block.page.lock.have_u_or_x());
+ return true;
+ }
+ }
+ }
+ return false;
}
/** Check if we are holding exclusive tablespace latch
@param space tablespace to search for
@param shared whether to look for shared latch, instead of exclusive
@return whether space.latch is being held */
-bool mtr_t::memo_contains(const fil_space_t& space, bool shared)
-{
- Iterate<Find> iteration(Find(&space, shared
- ? MTR_MEMO_SPACE_S_LOCK
- : MTR_MEMO_SPACE_X_LOCK));
- if (m_memo.for_each_block_in_reverse(iteration))
- return false;
- ut_ad(shared || space.is_owner());
- return true;
-}
-
-/** Upgrade U-latched pages to X */
-struct UpgradeX
+bool mtr_t::memo_contains(const fil_space_t& space, bool shared) const
{
- const buf_block_t &block;
- UpgradeX(const buf_block_t &block) : block(block) {}
- bool operator()(mtr_memo_slot_t *slot) const
+ if (m_memo)
{
- if (slot->object == &block && (MTR_MEMO_PAGE_SX_FIX & slot->type))
- slot->type= static_cast<mtr_memo_type_t>
- (slot->type ^ (MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX));
- return true;
+ const mtr_memo_type_t type= shared
+ ? MTR_MEMO_SPACE_S_LOCK : MTR_MEMO_SPACE_X_LOCK;
+
+ for (const mtr_memo_slot_t &slot : *m_memo)
+ {
+ if (slot.object == &space && slot.type == type)
+ {
+ ut_ad(shared || space.is_owner());
+ return true;
+ }
+ }
}
-};
-/** Upgrade U locks on a block to X */
+ return false;
+}
+
void mtr_t::page_lock_upgrade(const buf_block_t &block)
{
ut_ad(block.page.lock.have_x());
- m_memo.for_each_block(CIterate<UpgradeX>((UpgradeX(block))));
+ ut_ad(m_memo);
+
+ for (mtr_memo_slot_t &slot : *m_memo)
+ if (slot.object == &block && slot.type & MTR_MEMO_PAGE_SX_FIX)
+ slot.type= mtr_memo_type_t(slot.type ^
+ (MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX));
+
#ifdef BTR_CUR_HASH_ADAPT
ut_ad(!block.index || !block.index->freed());
#endif /* BTR_CUR_HASH_ADAPT */
}
-/** Upgrade U locks to X */
-struct UpgradeLockX
-{
- const index_lock &lock;
- UpgradeLockX(const index_lock &lock) : lock(lock) {}
- bool operator()(mtr_memo_slot_t *slot) const
- {
- if (slot->object == &lock && (MTR_MEMO_SX_LOCK & slot->type))
- slot->type= static_cast<mtr_memo_type_t>
- (slot->type ^ (MTR_MEMO_SX_LOCK | MTR_MEMO_X_LOCK));
- return true;
- }
-};
-
-/** Upgrade U locks on a block to X */
void mtr_t::lock_upgrade(const index_lock &lock)
{
ut_ad(lock.have_x());
- m_memo.for_each_block(CIterate<UpgradeLockX>((UpgradeLockX(lock))));
+ ut_ad(m_memo);
+
+ for (mtr_memo_slot_t &slot : *m_memo)
+ if (slot.object == &lock && slot.type == MTR_MEMO_SX_LOCK)
+ slot.type= MTR_MEMO_X_LOCK;
}
/** Latch a buffer pool block.
@@ -1654,232 +1302,240 @@ done:
memo_push(block, fix_type);
}
-#ifdef UNIV_DEBUG
-/** Check if we are holding an rw-latch in this mini-transaction
-@param lock latch to search for
-@param type held latch type
-@return whether (lock,type) is contained */
-bool mtr_t::memo_contains(const index_lock &lock, mtr_memo_type_t type)
+void mtr_t::upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch)
{
- Iterate<Find> iteration(Find(&lock, type));
- if (m_memo.for_each_block_in_reverse(iteration))
- return false;
+ ut_ad(is_active());
+ ut_ad(m_memo);
+ ut_ad(savepoint < m_memo->size());
- switch (type) {
- case MTR_MEMO_X_LOCK:
- ut_ad(lock.have_x());
- break;
- case MTR_MEMO_SX_LOCK:
- ut_ad(lock.have_u_or_x());
- break;
- case MTR_MEMO_S_LOCK:
- ut_ad(lock.have_s());
- break;
+ mtr_memo_slot_t &slot= (*m_memo)[savepoint];
+ ut_ad(slot.type == MTR_MEMO_BUF_FIX);
+ buf_block_t *block= static_cast<buf_block_t*>(slot.object);
+ ut_d(const auto state= block->page.state());
+ ut_ad(state > buf_page_t::UNFIXED);
+ ut_ad(state > buf_page_t::WRITE_FIX || state < buf_page_t::READ_FIX);
+
+ switch (rw_latch) {
default:
+ ut_ad("invalid state" == 0);
+ break;
+ case RW_SX_LATCH:
+ slot.type= MTR_MEMO_PAGE_SX_FIX;
+ block->page.lock.u_lock();
+ ut_ad(!block->page.is_io_fixed());
break;
+ case RW_X_LATCH:
+ slot.type= MTR_MEMO_PAGE_X_FIX;
+ block->page.lock.x_lock();
+ ut_ad(!block->page.is_io_fixed());
}
- return true;
+#ifdef BTR_CUR_HASH_ADAPT
+ btr_search_drop_page_hash_index(block, true);
+#endif
+ ut_ad(page_id_t(page_get_space_id(block->page.frame),
+ page_get_page_no(block->page.frame)) == block->page.id());
}
-/** Debug check for flags */
-struct FlaggedCheck {
- FlaggedCheck(const void* ptr, ulint flags)
- :
- m_ptr(ptr),
- m_flags(flags)
- {
- /* There must be some flags to look for. */
- ut_ad(flags);
- /* Look for rw-lock-related and page-related flags. */
- ut_ad(!(flags & ulint(~(MTR_MEMO_PAGE_S_FIX
- | MTR_MEMO_PAGE_X_FIX
- | MTR_MEMO_PAGE_SX_FIX
- | MTR_MEMO_BUF_FIX
- | MTR_MEMO_MODIFY
- | MTR_MEMO_X_LOCK
- | MTR_MEMO_SX_LOCK
- | MTR_MEMO_S_LOCK))));
- /* Either some rw-lock-related or page-related flags
- must be specified, but not both at the same time. */
- ut_ad(!(flags & (MTR_MEMO_PAGE_S_FIX
- | MTR_MEMO_PAGE_X_FIX
- | MTR_MEMO_PAGE_SX_FIX
- | MTR_MEMO_BUF_FIX
- | MTR_MEMO_MODIFY))
- == !!(flags & (MTR_MEMO_X_LOCK
- | MTR_MEMO_SX_LOCK
- | MTR_MEMO_S_LOCK)));
- }
+#ifdef UNIV_DEBUG
+/** Check if we are holding an rw-latch in this mini-transaction
+@param lock latch to search for
+@param type held latch type
+@return whether (lock,type) is contained */
+bool mtr_t::memo_contains(const index_lock &lock, mtr_memo_type_t type) const
+{
+ ut_ad(type == MTR_MEMO_X_LOCK || type == MTR_MEMO_S_LOCK ||
+ type == MTR_MEMO_SX_LOCK);
- /** Visit a memo entry.
- @param[in] slot memo entry to visit
- @retval false if m_ptr was found
- @retval true if the iteration should continue */
- bool operator()(const mtr_memo_slot_t* slot) const
- {
- if (m_ptr != slot->object) {
- return(true);
- }
-
- auto f = m_flags & slot->type;
- if (!f) {
- return true;
- }
-
- if (f & (MTR_MEMO_PAGE_S_FIX | MTR_MEMO_PAGE_SX_FIX
- | MTR_MEMO_PAGE_X_FIX)) {
- block_lock* lock = &static_cast<buf_block_t*>(
- const_cast<void*>(m_ptr))->page.lock;
- ut_ad(!(f & MTR_MEMO_PAGE_S_FIX) || lock->have_s());
- ut_ad(!(f & MTR_MEMO_PAGE_SX_FIX)
- || lock->have_u_or_x());
- ut_ad(!(f & MTR_MEMO_PAGE_X_FIX) || lock->have_x());
- } else {
- index_lock* lock = static_cast<index_lock*>(
- const_cast<void*>(m_ptr));
- ut_ad(!(f & MTR_MEMO_S_LOCK) || lock->have_s());
- ut_ad(!(f & MTR_MEMO_SX_LOCK) || lock->have_u_or_x());
- ut_ad(!(f & MTR_MEMO_X_LOCK) || lock->have_x());
- }
-
- return(false);
- }
+ if (m_memo)
+ {
+ for (const mtr_memo_slot_t &slot : *m_memo)
+ {
+ if (slot.object == &lock && slot.type == type)
+ {
+ switch (type) {
+ case MTR_MEMO_X_LOCK:
+ ut_ad(lock.have_x());
+ break;
+ case MTR_MEMO_SX_LOCK:
+ ut_ad(lock.have_u_or_x());
+ break;
+ case MTR_MEMO_S_LOCK:
+ ut_ad(lock.have_s());
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+ }
+ }
- const void*const m_ptr;
- const ulint m_flags;
-};
+ return false;
+}
/** Check if memo contains the given item.
@param object object to search
@param flags specify types of object (can be ORred) of
MTR_MEMO_PAGE_S_FIX ... values
@return true if contains */
-bool
-mtr_t::memo_contains_flagged(const void* ptr, ulint flags) const
+bool mtr_t::memo_contains_flagged(const void *object, ulint flags) const
{
- ut_ad(is_active());
+ ut_ad(is_active());
+ ut_ad(flags);
+ /* Look for rw-lock-related and page-related flags. */
+ ut_ad(!(flags & ulint(~(MTR_MEMO_PAGE_S_FIX | MTR_MEMO_PAGE_X_FIX |
+ MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_BUF_FIX |
+ MTR_MEMO_MODIFY | MTR_MEMO_X_LOCK |
+ MTR_MEMO_SX_LOCK | MTR_MEMO_S_LOCK))));
+ /* Either some rw-lock-related or page-related flags
+ must be specified, but not both at the same time. */
+ ut_ad(!(flags & (MTR_MEMO_PAGE_S_FIX | MTR_MEMO_PAGE_X_FIX |
+ MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_BUF_FIX |
+ MTR_MEMO_MODIFY)) ==
+ !!(flags & (MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK | MTR_MEMO_S_LOCK)));
+
+ for (const mtr_memo_slot_t &slot : *m_memo)
+ {
+ if (object != slot.object)
+ continue;
- return !m_memo.for_each_block_in_reverse(
- CIterate<FlaggedCheck>(FlaggedCheck(ptr, flags)));
-}
+ auto f = flags & slot.type;
+ if (!f)
+ continue;
-/** Check if memo contains the given page.
-@param[in] ptr pointer to within buffer frame
-@param[in] flags specify types of object with OR of
- MTR_MEMO_PAGE_S_FIX... values
-@return the block
-@retval NULL if not found */
-buf_block_t*
-mtr_t::memo_contains_page_flagged(
- const byte* ptr,
- ulint flags) const
-{
- Iterate<FindPage> iteration(FindPage(ptr, flags));
- return m_memo.for_each_block_in_reverse(iteration)
- ? NULL : iteration.functor.get_block();
-}
-#endif /* UNIV_DEBUG */
+ if (f & (MTR_MEMO_PAGE_S_FIX | MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX))
+ {
+ const block_lock &lock= static_cast<const buf_page_t*>(object)->lock;
+ ut_ad(!(f & MTR_MEMO_PAGE_S_FIX) || lock.have_s());
+ ut_ad(!(f & MTR_MEMO_PAGE_SX_FIX) || lock.have_u_or_x());
+ ut_ad(!(f & MTR_MEMO_PAGE_X_FIX) || lock.have_x());
+ }
+ else
+ {
+ const index_lock &lock= *static_cast<const index_lock*>(object);
+ ut_ad(!(f & MTR_MEMO_S_LOCK) || lock.have_s());
+ ut_ad(!(f & MTR_MEMO_SX_LOCK) || lock.have_u_or_x());
+ ut_ad(!(f & MTR_MEMO_X_LOCK) || lock.have_x());
+ }
+ return true;
+ }
+
+ return false;
+}
-/** Find a potentially modified block. */
-struct FindModified
+buf_block_t* mtr_t::memo_contains_page_flagged(const byte *ptr, ulint flags)
+ const
{
- mtr_memo_slot_t *found= nullptr;
- const buf_block_t& block;
+ ptr= page_align(ptr);
- FindModified(const buf_block_t &block) : block(block) {}
- bool operator()(mtr_memo_slot_t *slot)
+ for (const mtr_memo_slot_t &slot : *m_memo)
{
- if (slot->object != &block)
- return true;
- found= slot;
- return !(slot->type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
+ if (!slot.object || !(flags & slot.type))
+ continue;
+
+ buf_page_t *bpage= static_cast<buf_page_t*>(slot.object);
+
+ if (ptr != bpage->frame)
+ continue;
+
+ ut_ad(!(slot.type & MTR_MEMO_PAGE_S_FIX) || bpage->lock.have_s());
+ ut_ad(!(slot.type & MTR_MEMO_PAGE_SX_FIX) || bpage->lock.have_u_or_x());
+ ut_ad(!(slot.type & MTR_MEMO_PAGE_X_FIX) || bpage->lock.have_x());
+ return static_cast<buf_block_t*>(slot.object);
}
-};
+
+ return nullptr;
+}
+#endif /* UNIV_DEBUG */
+
/** Mark the given latched page as modified.
@param block page that will be modified */
void mtr_t::modify(const buf_block_t &block)
{
- if (UNIV_UNLIKELY(m_memo.empty()))
+ if (UNIV_UNLIKELY(!m_memo))
{
/* This must be PageConverter::update_page() in IMPORT TABLESPACE. */
ut_ad(!block.page.in_LRU_list);
return;
}
- Iterate<FindModified> iteration((FindModified(block)));
- m_memo.for_each_block(iteration);
- if (UNIV_UNLIKELY(!iteration.functor.found))
+ mtr_memo_slot_t *found= nullptr;
+
+ for (mtr_memo_slot_t &slot : *m_memo)
+ {
+ if (slot.object == &block &&
+ slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))
+ {
+ found= &slot;
+ break;
+ }
+ }
+
+ if (UNIV_UNLIKELY(!found))
{
ut_ad("modifying an unlatched page" == 0);
return;
}
- iteration.functor.found->type= static_cast<mtr_memo_type_t>
- (iteration.functor.found->type | MTR_MEMO_MODIFY);
- if (is_block_dirtied(&block))
- m_made_dirty= true;
+ found->type= static_cast<mtr_memo_type_t>(found->type | MTR_MEMO_MODIFY);
+ if (!m_made_dirty)
+ m_made_dirty= is_block_dirtied(block.page);
}
-/** Handle an exclusively latched block that was later marked as freed. */
-struct MarkFreed
+/** Free a page.
+@param space tablespace
+@param offset offset of the page to be freed */
+void mtr_t::free(const fil_space_t &space, uint32_t offset)
{
- const page_id_t id;
- mutable buf_block_t *freed= nullptr;
- MarkFreed(page_id_t id) : id(id) {}
+ ut_ad(is_named_space(&space));
+ ut_ad(!m_freed_space || m_freed_space == &space);
- bool operator()(mtr_memo_slot_t *slot) const
+ if (is_logged())
{
- buf_block_t *block= static_cast<buf_block_t*>(slot->object);
- if (!block);
- else if (block == freed)
+ ut_ad(m_memo);
+ buf_block_t *freed= nullptr;
+ const page_id_t id{space.id, offset};
+
+ for (auto it= m_memo->rbegin(); it != m_memo->rend(); it++)
{
- if (slot->type & (MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX))
- slot->type= MTR_MEMO_PAGE_X_FIX;
- else
+ mtr_memo_slot_t &slot= *it;
+ buf_block_t *block= static_cast<buf_block_t*>(slot.object);
+ if (!block);
+ else if (block == freed)
{
- ut_ad(slot->type == MTR_MEMO_BUF_FIX);
- block->page.unfix();
- slot->object= nullptr;
+ if (slot.type & (MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX))
+ slot.type= MTR_MEMO_PAGE_X_FIX;
+ else
+ {
+ ut_ad(slot.type == MTR_MEMO_BUF_FIX);
+ slot.object= nullptr;
+ block->page.unfix();
+ }
}
- }
- else if (slot->type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX) &&
- block->page.id() == id)
- {
- ut_ad(!block->page.is_freed());
- ut_ad(!freed);
- freed= block;
- if (!(slot->type & MTR_MEMO_PAGE_X_FIX))
+ else if (slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX) &&
+ block->page.id() == id)
{
- ut_d(bool upgraded=) block->page.lock.x_lock_upgraded();
- ut_ad(upgraded);
- }
- slot->type= MTR_MEMO_PAGE_X_MODIFY;
+ ut_ad(!block->page.is_freed());
+ ut_ad(!freed);
+ freed= block;
+ if (!(slot.type & MTR_MEMO_PAGE_X_FIX))
+ {
+ ut_d(bool upgraded=) block->page.lock.x_lock_upgraded();
+ ut_ad(upgraded);
+ }
+ slot.type= MTR_MEMO_PAGE_X_MODIFY;
#ifdef BTR_CUR_HASH_ADAPT
- if (block->index)
- btr_search_drop_page_hash_index(block);
+ if (block->index)
+ btr_search_drop_page_hash_index(block);
#endif /* BTR_CUR_HASH_ADAPT */
- block->page.set_freed(block->page.state());
+ block->page.set_freed(block->page.state());
+ }
}
- return true;
- }
-};
-
-/** Free a page.
-@param space tablespace
-@param offset offset of the page to be freed */
-void mtr_t::free(const fil_space_t &space, uint32_t offset)
-{
- ut_ad(is_named_space(&space));
- ut_ad(!m_freed_space || m_freed_space == &space);
- if (is_logged())
- {
- CIterate<MarkFreed> mf{MarkFreed{{space.id, offset}}};
- m_memo.for_each_block_in_reverse(mf);
- if (mf.functor.freed && !m_made_dirty)
- m_made_dirty= is_block_dirtied(mf.functor.freed);
- m_log.close(log_write<FREE_PAGE>({space.id, offset}, nullptr));
+ if (freed && !m_made_dirty)
+ m_made_dirty= is_block_dirtied(freed->page);
+ m_log.close(log_write<FREE_PAGE>(id, nullptr));
}
}
diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc
index 956256a2f43..b019694b9f6 100644
--- a/storage/innobase/page/page0cur.cc
+++ b/storage/innobase/page/page0cur.cc
@@ -277,8 +277,6 @@ Searches the right position for a page cursor. */
bool
page_cur_search_with_match(
/*=======================*/
- const buf_block_t* block, /*!< in: buffer block */
- const dict_index_t* index, /*!< in/out: record descriptor */
const dtuple_t* tuple, /*!< in: data tuple */
page_cur_mode_t mode, /*!< in: PAGE_CUR_L,
PAGE_CUR_LE, PAGE_CUR_G, or
@@ -303,6 +301,8 @@ page_cur_search_with_match(
ulint low_matched_fields;
ulint cur_matched_fields;
int cmp;
+ const dict_index_t* const index = cursor->index;
+ const buf_block_t* const block = cursor->block;
#ifdef UNIV_ZIP_DEBUG
const page_zip_des_t* page_zip = buf_block_get_page_zip(block);
#endif /* UNIV_ZIP_DEBUG */
@@ -552,8 +552,6 @@ first partially matched field in the lower limit record
@param[out] cursor page cursor */
bool
page_cur_search_with_match_bytes(
- const buf_block_t* block,
- const dict_index_t* index,
const dtuple_t* tuple,
page_cur_mode_t mode,
ulint* iup_matched_fields,
@@ -575,6 +573,8 @@ page_cur_search_with_match_bytes(
ulint cur_matched_fields;
ulint cur_matched_bytes;
int cmp;
+ const dict_index_t* const index = cursor->index;
+ const buf_block_t* const block = cursor->block;
#ifdef UNIV_ZIP_DEBUG
const page_zip_des_t* page_zip = buf_block_get_page_zip(block);
#endif /* UNIV_ZIP_DEBUG */
@@ -802,18 +802,13 @@ up_rec_match:
/***********************************************************//**
Positions a page cursor on a randomly chosen user record on a page. If there
are no user records, sets the cursor on the infimum record. */
-void
-page_cur_open_on_rnd_user_rec(
-/*==========================*/
- buf_block_t* block, /*!< in: page */
- page_cur_t* cursor) /*!< out: page cursor */
+void page_cur_open_on_rnd_user_rec(page_cur_t *cursor)
{
- cursor->block= block;
- if (const ulint n_recs= page_get_n_recs(block->page.frame))
- if ((cursor->rec= page_rec_get_nth(block->page.frame,
+ if (const ulint n_recs= page_get_n_recs(cursor->block->page.frame))
+ if ((cursor->rec= page_rec_get_nth(cursor->block->page.frame,
ut_rnd_interval(n_recs) + 1)))
return;
- cursor->rec= page_get_infimum_rec(block->page.frame);
+ cursor->rec= page_get_infimum_rec(cursor->block->page.frame);
}
/**
@@ -1361,12 +1356,12 @@ rec_t*
page_cur_insert_rec_low(
/*====================*/
const page_cur_t*cur, /*!< in: page cursor */
- dict_index_t* index, /*!< in: record descriptor */
const rec_t* rec, /*!< in: record to insert after cur */
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
- buf_block_t* block= cur->block;
+ buf_block_t *block= cur->block;
+ dict_index_t * const index= cur->index;
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(rec_offs_n_fields(offsets) > 0);
@@ -1786,13 +1781,13 @@ page_cur_insert_rec_zip(
/*====================*/
page_cur_t* cursor, /*!< in/out: page cursor,
logical position unchanged */
- dict_index_t* index, /*!< in: record descriptor */
const rec_t* rec, /*!< in: pointer to a physical record */
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
page_zip_des_t * const page_zip= page_cur_get_page_zip(cursor);
page_t * const page= cursor->block->page.frame;
+ dict_index_t * const index = cursor->index;
ut_ad(page_zip);
ut_ad(rec_offs_validate(rec, index, offsets));
@@ -1894,8 +1889,7 @@ page_cur_insert_rec_zip(
/* Try compressing the whole page afterwards. */
const mtr_log_t log_mode= mtr->set_log_mode(MTR_LOG_NONE);
- rec_t *insert_rec= page_cur_insert_rec_low(cursor, index, rec, offsets,
- mtr);
+ rec_t *insert_rec= page_cur_insert_rec_low(cursor, rec, offsets, mtr);
mtr->set_log_mode(log_mode);
if (insert_rec)
@@ -2243,7 +2237,6 @@ void
page_cur_delete_rec(
/*================*/
page_cur_t* cursor, /*!< in/out: a page cursor */
- const dict_index_t* index, /*!< in: record descriptor */
const rec_offs* offsets,/*!< in: rec_get_offsets(
cursor->rec, index) */
mtr_t* mtr) /*!< in/out: mini-transaction */
@@ -2265,6 +2258,7 @@ page_cur_delete_rec(
in the smallest user record, it cannot be used here either. */
current_rec = cursor->rec;
+ const dict_index_t* const index = cursor->index;
buf_block_t* const block = cursor->block;
ut_ad(rec_offs_validate(current_rec, index, offsets));
ut_ad(!!page_is_comp(block->page.frame)
diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc
index 3d4aaf9111f..127eb11f939 100644
--- a/storage/innobase/page/page0page.cc
+++ b/storage/innobase/page/page0page.cc
@@ -458,6 +458,7 @@ page_copy_rec_list_end_no_locks(
rec_offs* offsets = offsets_;
rec_offs_init(offsets_);
+ cur1.index = cur2.index = index;
page_cur_position(rec, block, &cur1);
if (page_cur_is_before_first(&cur1) && !page_cur_move_to_next(&cur1)) {
@@ -483,8 +484,8 @@ page_copy_rec_list_end_no_locks(
rec_t* ins_rec;
offsets = rec_get_offsets(cur1.rec, index, offsets, n_core,
ULINT_UNDEFINED, &heap);
- ins_rec = page_cur_insert_rec_low(&cur2, index,
- cur1.rec, offsets, mtr);
+ ins_rec = page_cur_insert_rec_low(&cur2, cur1.rec, offsets,
+ mtr);
if (UNIV_UNLIKELY(!ins_rec || !page_cur_move_to_next(&cur1))) {
err = DB_CORRUPTION;
break;
@@ -733,6 +734,7 @@ corrupted:
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
}
+ cur2.index = index;
page_cur_position(ret, new_block, &cur2);
const ulint n_core = page_rec_is_leaf(rec) ? index->n_core_fields : 0;
@@ -763,9 +765,8 @@ corrupted:
offsets = rec_get_offsets(cur1.rec, index, offsets,
n_core,
ULINT_UNDEFINED, &heap);
- cur2.rec = page_cur_insert_rec_low(&cur2, index,
- cur1.rec, offsets,
- mtr);
+ cur2.rec = page_cur_insert_rec_low(&cur2, cur1.rec,
+ offsets, mtr);
if (UNIV_UNLIKELY(!cur2.rec
|| !page_cur_move_to_next(&cur1))) {
*err = DB_CORRUPTION;
@@ -931,13 +932,14 @@ page_delete_rec_list_end(
{
page_cur_t cur;
page_cur_position(rec, block, &cur);
+ cur.index= index;
offsets= rec_get_offsets(rec, index, offsets, n_core,
ULINT_UNDEFINED, &heap);
rec= const_cast<rec_t*>(page_rec_get_next_low(rec, true));
#ifdef UNIV_ZIP_DEBUG
ut_a(page_zip_validate(&block->page.zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
- page_cur_delete_rec(&cur, index, offsets, mtr);
+ page_cur_delete_rec(&cur, offsets, mtr);
}
while (page_offset(rec) != PAGE_NEW_SUPREMUM);
@@ -1134,6 +1136,7 @@ page_delete_rec_list_start(
return;
}
+ cur1.index = index;
page_cur_set_before_first(block, &cur1);
if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
ut_ad("corrupted page" == 0);
@@ -1147,7 +1150,7 @@ page_delete_rec_list_start(
offsets = rec_get_offsets(page_cur_get_rec(&cur1), index,
offsets, n_core,
ULINT_UNDEFINED, &heap);
- page_cur_delete_rec(&cur1, index, offsets, mtr);
+ page_cur_delete_rec(&cur1, offsets, mtr);
}
if (UNIV_LIKELY_NULL(heap)) {
diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc
index c5fe7c04a17..5f5f527e06b 100644
--- a/storage/innobase/que/que0que.cc
+++ b/storage/innobase/que/que0que.cc
@@ -322,13 +322,9 @@ que_graph_free_recursive(
case QUE_NODE_UPDATE:
upd = static_cast<upd_node_t*>(node);
- if (upd->in_mysql_interface) {
-
- btr_pcur_free_for_mysql(upd->pcur);
- upd->in_mysql_interface = false;
- }
-
que_graph_free_recursive(upd->cascade_node);
+ ut_free(upd->pcur->old_rec_buf);
+ upd->pcur->old_rec_buf = NULL;
if (upd->cascade_heap) {
mem_heap_free(upd->cascade_heap);
diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc
index 9948f2e4d68..da6447c390e 100644
--- a/storage/innobase/rem/rem0rec.cc
+++ b/storage/innobase/rem/rem0rec.cc
@@ -611,7 +611,7 @@ rec_init_offsets(
ulint i = 0;
rec_offs offs;
- /* This assertion was relaxed for the btr_cur_open_at_index_side()
+ /* This assertion was relaxed for the btr_cur_t::open_leaf()
call in btr_cur_instant_init_low(). We cannot invoke
index->is_instant(), because the same assertion would fail there
until btr_cur_instant_init_low() has invoked
@@ -839,7 +839,7 @@ rec_get_offsets_func(
bool alter_metadata = false;
ut_ad(index->n_core_fields >= n_core);
- /* This assertion was relaxed for the btr_cur_open_at_index_side()
+ /* This assertion was relaxed for the btr_cur_t::open_leaf()
call in btr_cur_instant_init_low(). We cannot invoke
index->is_instant(), because the same assertion would fail there
until btr_cur_instant_init_low() has invoked
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index e11f4e8a26d..fbfe8a0f709 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -253,9 +253,10 @@ public:
}
/** Position the cursor on the first user record. */
- rec_t* open(buf_block_t* block) noexcept
+ rec_t* open(buf_block_t* block, const dict_index_t* index) noexcept
MY_ATTRIBUTE((warn_unused_result))
{
+ m_cur.index = const_cast<dict_index_t*>(index);
page_cur_set_before_first(block, &m_cur);
return next();
}
@@ -285,10 +286,9 @@ public:
/** Remove the current record
@return true on success */
- bool remove(
- const dict_index_t* index,
- rec_offs* offsets) UNIV_NOTHROW
+ bool remove(rec_offs* offsets) UNIV_NOTHROW
{
+ const dict_index_t* const index = m_cur.index;
ut_ad(page_is_leaf(m_cur.block->page.frame));
/* We can't end up with an empty page unless it is root. */
if (page_get_n_recs(m_cur.block->page.frame) <= 1) {
@@ -311,7 +311,7 @@ public:
page_zip, m_cur.block->page.frame, index));
#endif /* UNIV_ZIP_DEBUG */
- page_cur_delete_rec(&m_cur, index, offsets, &m_mtr);
+ page_cur_delete_rec(&m_cur, offsets, &m_mtr);
#ifdef UNIV_ZIP_DEBUG
ut_a(!page_zip || page_zip_validate(
@@ -1513,8 +1513,9 @@ inline bool IndexPurge::open() noexcept
m_mtr.start();
m_mtr.set_log_mode(MTR_LOG_NO_REDO);
- if (btr_pcur_open_at_index_side(true, m_index, BTR_MODIFY_LEAF,
- &m_pcur, true, 0, &m_mtr) != DB_SUCCESS)
+ btr_pcur_init(&m_pcur);
+
+ if (m_pcur.open_leaf(true, m_index, BTR_MODIFY_LEAF, &m_mtr) != DB_SUCCESS)
return false;
rec_t *rec= page_rec_get_next(btr_pcur_get_rec(&m_pcur));
@@ -1559,7 +1560,7 @@ dberr_t IndexPurge::next() noexcept
return DB_CORRUPTION;
}
/* The following is based on btr_pcur_move_to_next_user_rec(). */
- m_pcur.old_stored = false;
+ m_pcur.old_rec = nullptr;
ut_ad(m_pcur.latch_mode == BTR_MODIFY_LEAF);
do {
if (btr_pcur_is_after_last_on_page(&m_pcur)) {
@@ -1586,8 +1587,7 @@ tree structure may be changed during a pessimistic delete. */
inline dberr_t IndexPurge::purge_pessimistic_delete() noexcept
{
dberr_t err;
- if (m_pcur.restore_position(BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
- &m_mtr) != btr_pcur_t::CORRUPTED)
+ if (m_pcur.restore_position(BTR_PURGE_TREE, &m_mtr) != btr_pcur_t::CORRUPTED)
{
ut_ad(rec_get_deleted_flag(btr_pcur_get_rec(&m_pcur),
m_index->table->not_redundant()));
@@ -1722,10 +1722,8 @@ re-organising the B+tree.
@return true if purge succeeded */
inline bool PageConverter::purge() UNIV_NOTHROW
{
- const dict_index_t* index = m_index->m_srv_index;
-
/* We can't have a page that is empty and not root. */
- if (m_rec_iter.remove(index, m_offsets)) {
+ if (m_rec_iter.remove(m_offsets)) {
++m_index->m_stats.m_n_purged;
@@ -1789,7 +1787,7 @@ PageConverter::update_records(
/* This will also position the cursor on the first user record. */
- if (!m_rec_iter.open(block)) {
+ if (!m_rec_iter.open(block, m_index->m_srv_index)) {
return DB_CORRUPTION;
}
@@ -2289,8 +2287,8 @@ row_import_set_sys_max_row_id(
mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
- if (btr_pcur_open_at_index_side(false, index, BTR_SEARCH_LEAF,
- &pcur, true, 0, &mtr) == DB_SUCCESS) {
+ if (pcur.open_leaf(false, index, BTR_SEARCH_LEAF, &mtr)
+ == DB_SUCCESS) {
rec = btr_pcur_move_to_prev_on_page(&pcur);
if (!rec) {
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 7f9fbe896ee..827d31eee2f 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -174,7 +174,7 @@ dberr_t
row_ins_sec_index_entry_by_modify(
/*==============================*/
ulint flags, /*!< in: undo logging and locking flags */
- ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
+ ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_INSERT_TREE,
depending on whether mtr holds just a leaf
latch or also a tree latch */
btr_cur_t* cursor, /*!< in: B-tree cursor */
@@ -194,8 +194,8 @@ row_ins_sec_index_entry_by_modify(
rec = btr_cur_get_rec(cursor);
- ut_ad(!dict_index_is_clust(cursor->index));
- ut_ad(rec_offs_validate(rec, cursor->index, *offsets));
+ ut_ad(!cursor->index()->is_clust());
+ ut_ad(rec_offs_validate(rec, cursor->index(), *offsets));
ut_ad(!entry->info_bits);
/* We know that in the alphabetical ordering, entry and rec are
@@ -204,7 +204,7 @@ row_ins_sec_index_entry_by_modify(
difference. */
update = row_upd_build_sec_rec_difference_binary(
- rec, cursor->index, *offsets, entry, heap);
+ rec, cursor->index(), *offsets, entry, heap);
if (!rec_get_deleted_flag(rec, rec_offs_comp(*offsets))) {
/* We should never insert in place of a record that
@@ -218,8 +218,8 @@ row_ins_sec_index_entry_by_modify(
returns. After that point, set_committed(true)
would be invoked in commit_inplace_alter_table(). */
ut_a(update->n_fields == 0);
- ut_a(!cursor->index->is_committed());
- ut_ad(!dict_index_is_online_ddl(cursor->index));
+ ut_a(!cursor->index()->is_committed());
+ ut_ad(!dict_index_is_online_ddl(cursor->index()));
return(DB_SUCCESS);
}
@@ -241,7 +241,7 @@ row_ins_sec_index_entry_by_modify(
break;
}
} else {
- ut_a(mode == BTR_MODIFY_TREE);
+ ut_ad(mode == BTR_INSERT_TREE);
if (buf_pool.running_out()) {
return(DB_LOCK_TABLE_FULL);
@@ -288,15 +288,15 @@ row_ins_clust_index_entry_by_modify(
dberr_t err = DB_SUCCESS;
btr_cur_t* cursor = btr_pcur_get_btr_cur(pcur);
TABLE* mysql_table = NULL;
- ut_ad(dict_index_is_clust(cursor->index));
+ ut_ad(cursor->index()->is_clust());
rec = btr_cur_get_rec(cursor);
ut_ad(rec_get_deleted_flag(rec,
- dict_table_is_comp(cursor->index->table)));
+ cursor->index()->table->not_redundant()));
/* In delete-marked records, DB_TRX_ID must
always refer to an existing undo log record. */
- ut_ad(rec_get_trx_id(rec, cursor->index));
+ ut_ad(rec_get_trx_id(rec, cursor->index()));
/* Build an update vector containing all the fields to be modified;
NOTE that this vector may NOT contain system columns trx_id or
@@ -307,7 +307,7 @@ row_ins_clust_index_entry_by_modify(
}
update = row_upd_build_difference_binary(
- cursor->index, entry, rec, NULL, true, true,
+ cursor->index(), entry, rec, NULL, true, true,
thr_get_trx(thr), heap, mysql_table, &err);
if (err != DB_SUCCESS) {
return(err);
@@ -1115,7 +1115,7 @@ row_ins_foreign_check_on_constraint(
goto nonstandard_exit_func;
}
- index = btr_pcur_get_btr_cur(pcur)->index;
+ index = pcur->index();
ut_a(index == foreign->foreign_index);
@@ -1138,7 +1138,9 @@ row_ins_foreign_check_on_constraint(
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec,
tmp_heap);
- err = btr_pcur_open_with_no_init(clust_index, ref,
+ cascade->pcur->old_rec = nullptr;
+ cascade->pcur->btr_cur.page_cur.index = clust_index;
+ err = btr_pcur_open_with_no_init(ref,
PAGE_CUR_LE, BTR_SEARCH_LEAF,
cascade->pcur, mtr);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
@@ -1622,9 +1624,9 @@ row_ins_check_foreign_constraint(
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
-
- err = btr_pcur_open(check_index, entry, PAGE_CUR_GE,
- BTR_SEARCH_LEAF, &pcur, &mtr);
+ pcur.btr_cur.page_cur.index = check_index;
+ err = btr_pcur_open(entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, 0,
+ &mtr);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
goto end_scan;
}
@@ -2064,9 +2066,9 @@ row_ins_scan_sec_index_for_duplicate(
dtuple_set_n_fields_cmp(entry, n_unique);
const auto allow_duplicates = thr_get_trx(thr)->duplicates;
-
- dberr_t err = btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF,
- &pcur, mtr);
+ pcur.btr_cur.page_cur.index = index;
+ dberr_t err = btr_pcur_open(entry, PAGE_CUR_GE, BTR_SEARCH_LEAF,
+ &pcur, 0, mtr);
if (err != DB_SUCCESS) {
goto end_scan;
}
@@ -2220,14 +2222,14 @@ row_ins_duplicate_error_in_clust_online(
dberr_t err = DB_SUCCESS;
const rec_t* rec = btr_cur_get_rec(cursor);
- ut_ad(!cursor->index->is_instant());
+ ut_ad(!cursor->index()->is_instant());
if (cursor->low_match >= n_uniq && !page_rec_is_infimum(rec)) {
- *offsets = rec_get_offsets(rec, cursor->index, *offsets,
- cursor->index->n_fields,
+ *offsets = rec_get_offsets(rec, cursor->index(), *offsets,
+ cursor->index()->n_fields,
ULINT_UNDEFINED, heap);
err = row_ins_duplicate_online(n_uniq, entry,
- rec, cursor->index, *offsets);
+ rec, cursor->index(), *offsets);
if (err != DB_SUCCESS) {
return(err);
}
@@ -2238,11 +2240,11 @@ row_ins_duplicate_error_in_clust_online(
}
if (cursor->up_match >= n_uniq && !page_rec_is_supremum(rec)) {
- *offsets = rec_get_offsets(rec, cursor->index, *offsets,
- cursor->index->n_fields,
+ *offsets = rec_get_offsets(rec, cursor->index(), *offsets,
+ cursor->index()->n_fields,
ULINT_UNDEFINED, heap);
err = row_ins_duplicate_online(n_uniq, entry,
- rec, cursor->index, *offsets);
+ rec, cursor->index(), *offsets);
}
return(err);
@@ -2273,7 +2275,7 @@ row_ins_duplicate_error_in_clust(
rec_offs* offsets = offsets_;
rec_offs_init(offsets_);
- ut_ad(dict_index_is_clust(cursor->index));
+ ut_ad(cursor->index()->is_clust());
/* NOTE: For unique non-clustered indexes there may be any number
of delete marked records with the same value for the non-clustered
@@ -2288,15 +2290,17 @@ row_ins_duplicate_error_in_clust(
user records on the leaf level. So, even if low_match would suggest
that a duplicate key violation may occur, this may not be the case. */
- n_unique = dict_index_get_n_unique(cursor->index);
+ n_unique = dict_index_get_n_unique(cursor->index());
if (cursor->low_match >= n_unique) {
rec = btr_cur_get_rec(cursor);
if (!page_rec_is_infimum(rec)) {
- offsets = rec_get_offsets(rec, cursor->index, offsets,
- cursor->index->n_core_fields,
+ offsets = rec_get_offsets(rec, cursor->index(),
+ offsets,
+ cursor->index()
+ ->n_core_fields,
ULINT_UNDEFINED, &heap);
/* We set a lock on the possible duplicate: this
@@ -2317,13 +2321,13 @@ row_ins_duplicate_error_in_clust(
err = row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP,
btr_cur_get_block(cursor),
- rec, cursor->index, offsets, thr);
+ rec, cursor->index(), offsets, thr);
} else {
err = row_ins_set_shared_rec_lock(
LOCK_REC_NOT_GAP,
btr_cur_get_block(cursor), rec,
- cursor->index, offsets, thr);
+ cursor->index(), offsets, thr);
}
switch (err) {
@@ -2335,11 +2339,11 @@ row_ins_duplicate_error_in_clust(
}
if (row_ins_dupl_error_with_rec(
- rec, entry, cursor->index, offsets)) {
+ rec, entry, cursor->index(), offsets)) {
duplicate:
- trx->error_info = cursor->index;
+ trx->error_info = cursor->index();
err = DB_DUPLICATE_KEY;
- if (cursor->index->table->versioned()
+ if (cursor->index()->table->versioned()
&& entry->vers_history_row())
{
ulint trx_id_len;
@@ -2363,8 +2367,10 @@ duplicate:
rec = page_rec_get_next(btr_cur_get_rec(cursor));
if (rec && !page_rec_is_supremum(rec)) {
- offsets = rec_get_offsets(rec, cursor->index, offsets,
- cursor->index->n_core_fields,
+ offsets = rec_get_offsets(rec, cursor->index(),
+ offsets,
+ cursor->index()
+ ->n_core_fields,
ULINT_UNDEFINED, &heap);
if (trx->duplicates) {
@@ -2377,13 +2383,13 @@ duplicate:
err = row_ins_set_exclusive_rec_lock(
LOCK_REC_NOT_GAP,
btr_cur_get_block(cursor),
- rec, cursor->index, offsets, thr);
+ rec, cursor->index(), offsets, thr);
} else {
err = row_ins_set_shared_rec_lock(
LOCK_REC_NOT_GAP,
btr_cur_get_block(cursor),
- rec, cursor->index, offsets, thr);
+ rec, cursor->index(), offsets, thr);
}
switch (err) {
@@ -2394,7 +2400,7 @@ duplicate:
/* fall through */
case DB_SUCCESS:
if (row_ins_dupl_error_with_rec(
- rec, entry, cursor->index,
+ rec, entry, cursor->index(),
offsets)) {
goto duplicate;
}
@@ -2436,7 +2442,7 @@ row_ins_must_modify_rec(
and a secondary index node pointer contains all index fields. */
return(cursor->low_match
- >= dict_index_get_n_unique_in_tree(cursor->index)
+ >= dict_index_get_n_unique_in_tree(cursor->index())
&& !page_rec_is_infimum(btr_cur_get_rec(cursor)));
}
@@ -2465,6 +2471,7 @@ row_ins_index_entry_big_rec(
btr_pcur_t pcur;
rec_t* rec;
+ pcur.btr_cur.page_cur.index = index;
ut_ad(index->is_primary());
DEBUG_SYNC_C_IF_THD(thd, "before_row_ins_extern_latch");
@@ -2476,8 +2483,8 @@ row_ins_index_entry_big_rec(
index->set_modified(mtr);
}
- dberr_t error = btr_pcur_open(index, entry, PAGE_CUR_LE,
- BTR_MODIFY_TREE, &pcur, &mtr);
+ dberr_t error = btr_pcur_open(entry, PAGE_CUR_LE,
+ BTR_MODIFY_TREE, &pcur, 0, &mtr);
if (error != DB_SUCCESS) {
return error;
}
@@ -2525,7 +2532,7 @@ dberr_t
row_ins_clust_index_entry_low(
/*==========================*/
ulint flags, /*!< in: undo logging and locking flags */
- ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
depending on whether we wish optimistic or
pessimistic descent down the index tree */
dict_index_t* index, /*!< in: clustered index */
@@ -2578,7 +2585,7 @@ row_ins_clust_index_entry_low(
} else {
if (mode == BTR_MODIFY_LEAF
&& dict_index_is_online_ddl(index)) {
- mode = BTR_MODIFY_LEAF_ALREADY_S_LATCHED;
+ mode = BTR_MODIFY_LEAF_ALREADY_LATCHED;
mtr_s_lock_index(index, &mtr);
}
@@ -2603,8 +2610,8 @@ row_ins_clust_index_entry_low(
/* Note that we use PAGE_CUR_LE as the search mode, because then
the function will return in both low_match and up_match of the
cursor sensible values */
- err = btr_pcur_open_low(index, 0, entry, PAGE_CUR_LE, mode, &pcur,
- auto_inc, &mtr);
+ pcur.btr_cur.page_cur.index = index;
+ err = btr_pcur_open(entry, PAGE_CUR_LE, mode, &pcur, auto_inc, &mtr);
if (err != DB_SUCCESS) {
index->table->file_unreadable = true;
commit_exit:
@@ -2732,7 +2739,7 @@ skip_bulk_insert:
/* fall through */
case DB_SUCCESS_LOCKED_REC:
case DB_DUPLICATE_KEY:
- trx->error_info = cursor->index;
+ trx->error_info = cursor->index();
}
} else {
/* Note that the following may return also
@@ -2769,8 +2776,8 @@ do_insert:
rec_t* insert_rec;
if (mode != BTR_MODIFY_TREE) {
- ut_ad((mode & ulint(~BTR_ALREADY_S_LATCHED))
- == BTR_MODIFY_LEAF);
+ ut_ad(mode == BTR_MODIFY_LEAF ||
+ mode == BTR_MODIFY_LEAF_ALREADY_LATCHED);
err = btr_cur_optimistic_insert(
flags, cursor, &offsets, &offsets_heap,
entry, &insert_rec, &big_rec,
@@ -2846,13 +2853,13 @@ same fields is found, the other record is necessarily marked deleted.
It is then unmarked. Otherwise, the entry is just inserted to the index.
@retval DB_SUCCESS on success
@retval DB_LOCK_WAIT on lock wait when !(flags & BTR_NO_LOCKING_FLAG)
-@retval DB_FAIL if retry with BTR_MODIFY_TREE is needed
+@retval DB_FAIL if retry with BTR_INSERT_TREE is needed
@return error code */
dberr_t
row_ins_sec_index_entry_low(
/*========================*/
ulint flags, /*!< in: undo logging and locking flags */
- ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_INSERT_TREE,
depending on whether we wish optimistic or
pessimistic descent down the index tree */
dict_index_t* index, /*!< in: secondary index */
@@ -2867,7 +2874,7 @@ row_ins_sec_index_entry_low(
DBUG_ENTER("row_ins_sec_index_entry_low");
btr_cur_t cursor;
- ulint search_mode = mode;
+ btr_latch_mode search_mode = mode;
dberr_t err;
ulint n_unique;
mtr_t mtr;
@@ -2877,10 +2884,11 @@ row_ins_sec_index_entry_low(
rtr_info_t rtr_info;
ut_ad(!dict_index_is_clust(index));
- ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE);
+ ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_INSERT_TREE);
cursor.thr = thr;
cursor.rtr_info = NULL;
+ cursor.page_cur.index = index;
ut_ad(thr_get_trx(thr)->id != 0);
mtr.start();
@@ -2892,24 +2900,19 @@ row_ins_sec_index_entry_low(
mtr.set_log_mode(MTR_LOG_NO_REDO);
} else {
index->set_modified(mtr);
- if (!dict_index_is_spatial(index)) {
- search_mode |= BTR_INSERT;
- }
}
/* Note that we use PAGE_CUR_LE as the search mode, because then
the function will return in both low_match and up_match of the
cursor sensible values */
- if (dict_index_is_spatial(index)) {
- cursor.index = index;
+ if (index->is_spatial()) {
rtr_init_rtr_info(&rtr_info, false, &cursor, index, false);
rtr_info_update_btr(&cursor, &rtr_info);
- err = btr_cur_search_to_nth_level(
- index, 0, entry, PAGE_CUR_RTREE_INSERT,
- search_mode,
- &cursor, &mtr);
+ err = btr_cur_search_to_nth_level(0, entry,
+ PAGE_CUR_RTREE_INSERT,
+ search_mode, &cursor, &mtr);
if (err == DB_SUCCESS && search_mode == BTR_MODIFY_LEAF
&& rtr_info.mbr_adj) {
@@ -2926,9 +2929,8 @@ row_ins_sec_index_entry_low(
index->set_modified(mtr);
}
err = btr_cur_search_to_nth_level(
- index, 0, entry, PAGE_CUR_RTREE_INSERT,
- search_mode,
- &cursor, &mtr);
+ 0, entry, PAGE_CUR_RTREE_INSERT,
+ search_mode, &cursor, &mtr);
}
DBUG_EXECUTE_IF(
@@ -2936,14 +2938,16 @@ row_ins_sec_index_entry_low(
goto func_exit;});
} else {
- if (!thr_get_trx(thr)->check_unique_secondary) {
- search_mode |= BTR_IGNORE_SEC_UNIQUE;
+ if (!index->table->is_temporary()) {
+ search_mode = btr_latch_mode(
+ search_mode
+ | (thr_get_trx(thr)->check_unique_secondary
+ ? BTR_INSERT | BTR_IGNORE_SEC_UNIQUE
+ : BTR_INSERT));
}
- err = btr_cur_search_to_nth_level(
- index, 0, entry, PAGE_CUR_LE,
- search_mode,
- &cursor, &mtr);
+ err = btr_cur_search_to_nth_level(0, entry, PAGE_CUR_LE,
+ search_mode, &cursor, &mtr);
}
if (err != DB_SUCCESS) {
@@ -3018,11 +3022,12 @@ row_ins_sec_index_entry_low(
locked with s-locks the necessary records to
prevent any insertion of a duplicate by another
transaction. Let us now reposition the cursor and
- continue the insertion. */
+ continue the insertion (bypassing the change buffer). */
err = btr_cur_search_to_nth_level(
- index, 0, entry, PAGE_CUR_LE,
- (search_mode
- & ~(BTR_INSERT | BTR_IGNORE_SEC_UNIQUE)),
+ 0, entry, PAGE_CUR_LE,
+ btr_latch_mode(search_mode
+ & ~(BTR_INSERT
+ | BTR_IGNORE_SEC_UNIQUE)),
&cursor, &mtr);
if (err != DB_SUCCESS) {
goto func_exit;
@@ -3061,7 +3066,6 @@ row_ins_sec_index_entry_low(
err = rtr_ins_enlarge_mbr(&cursor, &mtr);
}
} else {
- ut_ad(mode == BTR_MODIFY_TREE);
if (buf_pool.running_out()) {
err = DB_LOCK_TABLE_FULL;
goto func_exit;
@@ -3264,7 +3268,7 @@ row_ins_sec_index_entry(
log_free_check();
err = row_ins_sec_index_entry_low(
- flags, BTR_MODIFY_TREE, index,
+ flags, BTR_INSERT_TREE, index,
offsets_heap, heap, entry, 0, thr);
}
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index ff190bd0779..404aa8edafb 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -1583,7 +1583,7 @@ row_log_table_apply_insert_low(
entry = row_build_index_entry(row, NULL, index, heap);
error = row_ins_sec_index_entry_low(
- flags, BTR_MODIFY_TREE,
+ flags, BTR_INSERT_TREE,
index, offsets_heap, heap, entry,
thr_get_trx(thr)->id, thr);
@@ -1658,7 +1658,7 @@ row_log_table_apply_delete_low(
dberr_t error;
row_ext_t* ext;
dtuple_t* row;
- dict_index_t* index = btr_pcur_get_btr_cur(pcur)->index;
+ dict_index_t* index = pcur->index();
ut_ad(dict_index_is_clust(index));
@@ -1695,9 +1695,9 @@ err_exit:
row, ext, index, heap);
mtr->start();
index->set_modified(*mtr);
- error = btr_pcur_open(index, entry, PAGE_CUR_LE,
- BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
- pcur, mtr);
+ pcur->btr_cur.page_cur.index = index;
+ error = btr_pcur_open(entry, PAGE_CUR_LE,
+ BTR_PURGE_TREE, pcur, 0, mtr);
if (error) {
goto err_exit;
}
@@ -1761,6 +1761,7 @@ row_log_table_apply_delete(
btr_pcur_t pcur;
rec_offs* offsets;
+ pcur.btr_cur.page_cur.index = index;
ut_ad(rec_offs_n_fields(moffsets) == index->first_user_field());
ut_ad(!rec_offs_any_extern(moffsets));
@@ -1779,9 +1780,8 @@ row_log_table_apply_delete(
mtr_start(&mtr);
index->set_modified(mtr);
- dberr_t err = btr_pcur_open(index, old_pk, PAGE_CUR_LE,
- BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
- &pcur, &mtr);
+ dberr_t err = btr_pcur_open(old_pk, PAGE_CUR_LE,
+ BTR_PURGE_TREE, &pcur, 0, &mtr);
if (err != DB_SUCCESS) {
goto all_done;
}
@@ -1893,6 +1893,8 @@ row_log_table_apply_update(
dberr_t error;
ulint n_index = 0;
+ pcur.btr_cur.page_cur.index = index;
+
ut_ad(dtuple_get_n_fields_cmp(old_pk)
== dict_index_get_n_unique(index));
ut_ad(dtuple_get_n_fields(old_pk) - (log->same_pk ? 0 : 2)
@@ -1915,8 +1917,8 @@ row_log_table_apply_update(
mtr.start();
index->set_modified(mtr);
- error = btr_pcur_open(index, old_pk, PAGE_CUR_LE,
- BTR_MODIFY_TREE, &pcur, &mtr);
+ error = btr_pcur_open(old_pk, PAGE_CUR_LE,
+ BTR_MODIFY_TREE, &pcur, 0, &mtr);
if (error != DB_SUCCESS) {
func_exit:
mtr.commit();
@@ -2061,7 +2063,7 @@ func_exit_committed:
for (n_index += index->type != DICT_CLUSTERED;
(index = dict_table_get_next_index(index)); n_index++) {
- if (index->type & DICT_FTS) {
+ if (!index->is_btree()) {
continue;
}
@@ -2089,9 +2091,10 @@ func_exit_committed:
mtr.start();
index->set_modified(mtr);
+ pcur.btr_cur.page_cur.index = index;
if (ROW_FOUND != row_search_index_entry(
- index, entry, BTR_MODIFY_TREE, &pcur, &mtr)) {
+ entry, BTR_MODIFY_TREE, &pcur, &mtr)) {
ut_ad(0);
error = DB_CORRUPTION;
break;
@@ -2111,7 +2114,7 @@ func_exit_committed:
error = row_ins_sec_index_entry_low(
BTR_CREATE_FLAG | BTR_NO_LOCKING_FLAG
| BTR_NO_UNDO_LOG_FLAG | BTR_KEEP_SYS_FLAG,
- BTR_MODIFY_TREE, index, offsets_heap, heap,
+ BTR_INSERT_TREE, index, offsets_heap, heap,
entry, thr_get_trx(thr)->id, thr);
/* Report correct index name for duplicate key error. */
@@ -3071,13 +3074,14 @@ row_log_apply_op_low(
mtr_start(&mtr);
index->set_modified(mtr);
+ cursor.page_cur.index = index;
/* We perform the pessimistic variant of the operations if we
already hold index->lock exclusively. First, search the
record. The operation may already have been performed,
depending on when the row in the clustered index was
scanned. */
- *error = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
+ *error = btr_cur_search_to_nth_level(0, entry, PAGE_CUR_LE,
has_index_lock
? BTR_MODIFY_TREE
: BTR_MODIFY_LEAF,
@@ -3132,7 +3136,7 @@ row_log_apply_op_low(
mtr_start(&mtr);
index->set_modified(mtr);
*error = btr_cur_search_to_nth_level(
- index, 0, entry, PAGE_CUR_LE,
+ 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, &mtr);
if (UNIV_UNLIKELY(*error != DB_SUCCESS)) {
goto func_exit;
@@ -3236,7 +3240,7 @@ insert_the_rec:
mtr_start(&mtr);
index->set_modified(mtr);
*error = btr_cur_search_to_nth_level(
- index, 0, entry, PAGE_CUR_LE,
+ 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, &mtr);
if (*error != DB_SUCCESS) {
break;
@@ -3951,8 +3955,8 @@ void UndorecApplier::log_insert(const dtuple_t &tuple,
}
bool success= true;
- dict_index_t *index= dict_table_get_next_index(clust_index);
- while (index)
+ for (dict_index_t *index= clust_index;
+ (index= dict_table_get_next_index(index)) != nullptr; )
{
index->lock.s_lock(SRW_LOCK_CALL);
if (index->online_log &&
@@ -3971,7 +3975,6 @@ void UndorecApplier::log_insert(const dtuple_t &tuple,
row_log_mark_other_online_index_abort(index->table);
return;
}
- index= dict_table_get_next_index(index);
}
}
}
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index f9fef9747c6..a10e67850d9 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -145,13 +145,13 @@ public:
mtr.start();
index->set_modified(mtr);
- ins_cur.index = index;
+ ins_cur.page_cur.index = index;
rtr_init_rtr_info(&rtr_info, false, &ins_cur, index,
false);
rtr_info_update_btr(&ins_cur, &rtr_info);
error = btr_cur_search_to_nth_level(
- index, 0, dtuple, PAGE_CUR_RTREE_INSERT,
+ 0, dtuple, PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_LEAF, &ins_cur, &mtr);
/* It need to update MBR in parent entry,
@@ -165,7 +165,7 @@ public:
mtr.start();
index->set_modified(mtr);
error = btr_cur_search_to_nth_level(
- index, 0, dtuple,
+ 0, dtuple,
PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE, &ins_cur, &mtr);
}
@@ -190,7 +190,7 @@ public:
rtr_info_update_btr(&ins_cur, &rtr_info);
error = btr_cur_search_to_nth_level(
- index, 0, dtuple,
+ 0, dtuple,
PAGE_CUR_RTREE_INSERT,
BTR_MODIFY_TREE,
&ins_cur, &mtr);
@@ -1999,8 +1999,7 @@ row_merge_read_clustered_index(
? col_map[old_trx_id_col] : old_trx_id_col;
uint64_t n_rows = 0;
- err = btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF,
- &pcur, true, 0, &mtr);
+ err = pcur.open_leaf(true, clust_index, BTR_SEARCH_LEAF, &mtr);
if (err != DB_SUCCESS) {
err_exit:
trx->error_key_num = 0;
@@ -2232,13 +2231,15 @@ end_of_index:
if (!block) {
goto err_exit;
}
- btr_leaf_page_release(page_cur_get_block(cur),
- BTR_SEARCH_LEAF, &mtr);
+
page_cur_set_before_first(block, cur);
if (!page_cur_move_to_next(cur)
|| page_cur_is_after_last(cur)) {
goto corrupted_rec;
}
+
+ const auto s = mtr.get_savepoint();
+ mtr.rollback_to_savepoint(s - 2, s - 1);
}
} else {
mem_heap_empty(row_heap);
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index de469c5b088..6ac0d26bb2a 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -1456,11 +1456,8 @@ row_create_update_node_for_mysql(
node->in_mysql_interface = true;
node->is_delete = NO_DELETE;
- node->searched_update = FALSE;
- node->select = NULL;
- node->pcur = btr_pcur_create_for_mysql();
-
- DBUG_PRINT("info", ("node: %p, pcur: %p", node, node->pcur));
+ node->pcur = new (mem_heap_alloc(heap, sizeof(btr_pcur_t)))
+ btr_pcur_t();
node->table = table;
@@ -1472,10 +1469,6 @@ row_create_update_node_for_mysql(
UT_LIST_INIT(node->columns, &sym_node_t::col_var_list);
node->has_clust_rec_x_lock = TRUE;
- node->cmpl_info = 0;
-
- node->table_sym = NULL;
- node->col_assign_list = NULL;
DBUG_RETURN(node);
}
@@ -1650,8 +1643,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt)
clust_index = dict_table_get_first_index(table);
btr_pcur_copy_stored_position(node->pcur,
- prebuilt->pcur->btr_cur.index
- == clust_index
+ prebuilt->pcur->index() == clust_index
? prebuilt->pcur
: prebuilt->clust_pcur);
@@ -1804,7 +1796,7 @@ row_unlock_for_mysql(
}
rec = btr_pcur_get_rec(pcur);
- index = btr_pcur_get_btr_cur(pcur)->index;
+ index = pcur->index();
/* If the record has been modified by this
transaction, do not unlock it. */
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index b60b21d2aff..df042f66521 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -67,7 +67,7 @@ static
ibool
row_purge_reposition_pcur(
/*======================*/
- ulint mode, /*!< in: latching mode */
+ btr_latch_mode mode, /*!< in: latching mode */
purge_node_t* node, /*!< in: row purge node */
mtr_t* mtr) /*!< in: mtr */
{
@@ -104,7 +104,7 @@ bool
row_purge_remove_clust_if_poss_low(
/*===============================*/
purge_node_t* node, /*!< in/out: row purge node */
- ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
+ btr_latch_mode mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
{
dict_index_t* index = dict_table_get_first_index(node->table);
table_id_t table_id = 0;
@@ -216,7 +216,7 @@ close_and_exit:
btr_pcur_get_btr_cur(&node->pcur), 0, &mtr);
} else {
dberr_t err;
- ut_ad(mode == (BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE));
+ ut_ad(mode == BTR_PURGE_TREE);
btr_cur_pessimistic_delete(
&err, FALSE, btr_pcur_get_btr_cur(&node->pcur), 0,
false, &mtr);
@@ -257,8 +257,7 @@ row_purge_remove_clust_if_poss(
for (ulint n_tries = 0;
n_tries < BTR_CUR_RETRY_DELETE_N_TIMES;
n_tries++) {
- if (row_purge_remove_clust_if_poss_low(
- node, BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE)) {
+ if (row_purge_remove_clust_if_poss_low(node, BTR_PURGE_TREE)) {
return(true);
}
@@ -348,11 +347,10 @@ row_purge_remove_sec_if_poss_tree(
log_free_check();
mtr.start();
index->set_modified(mtr);
+ pcur.btr_cur.page_cur.index = index;
- search_result = row_search_index_entry(
- index, entry,
- BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
- &pcur, &mtr);
+ search_result = row_search_index_entry(entry, BTR_PURGE_TREE,
+ &pcur, &mtr);
switch (search_result) {
case ROW_NOT_FOUND:
@@ -455,6 +453,7 @@ row_purge_remove_sec_if_poss_leaf(
virtual index. */
mode = (index->type & (DICT_SPATIAL | DICT_VIRTUAL))
? BTR_MODIFY_LEAF : BTR_PURGE_LEAF;
+ pcur.btr_cur.page_cur.index = index;
/* Set the purge node for the call to row_purge_poss_sec(). */
pcur.btr_cur.purge_node = node;
@@ -462,7 +461,7 @@ row_purge_remove_sec_if_poss_leaf(
pcur.btr_cur.thr = NULL;
index->lock.u_lock(SRW_LOCK_CALL);
search_result = row_search_index_entry(
- index, entry, mode, &pcur, &mtr);
+ entry, mode, &pcur, &mtr);
index->lock.u_unlock();
} else {
/* Set the query thread, so that ibuf_insert_low() will be
@@ -470,7 +469,7 @@ row_purge_remove_sec_if_poss_leaf(
pcur.btr_cur.thr = static_cast<que_thr_t*>(
que_node_get_parent(node));
search_result = row_search_index_entry(
- index, entry, mode, &pcur, &mtr);
+ entry, mode, &pcur, &mtr);
}
switch (search_result) {
@@ -1343,11 +1342,11 @@ purge_node_t::validate_pcur()
return(true);
}
- if (!pcur.old_stored) {
+ if (!pcur.old_rec) {
return(true);
}
- dict_index_t* clust_index = pcur.btr_cur.index;
+ dict_index_t* clust_index = pcur.index();
rec_offs* offsets = rec_get_offsets(
pcur.old_rec, clust_index, NULL, pcur.old_n_core_fields,
diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc
index 9218e739e96..599033353c5 100644
--- a/storage/innobase/row/row0row.cc
+++ b/storage/innobase/row/row0row.cc
@@ -1183,32 +1183,28 @@ row_build_row_ref_in_tuple(
/***************************************************************//**
Searches the clustered index record for a row, if we have the row reference.
@return TRUE if found */
-ibool
+bool
row_search_on_row_ref(
/*==================*/
btr_pcur_t* pcur, /*!< out: persistent cursor, which must
be closed by the caller */
- ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */
const dict_table_t* table, /*!< in: table */
const dtuple_t* ref, /*!< in: row reference */
mtr_t* mtr) /*!< in/out: mtr */
{
- ulint low_match;
- rec_t* rec;
- dict_index_t* index;
-
ut_ad(dtuple_check_typed(ref));
- index = dict_table_get_first_index(table);
+ dict_index_t *index = dict_table_get_first_index(table);
+ btr_pcur_init(pcur);
+ pcur->btr_cur.page_cur.index = index;
if (UNIV_UNLIKELY(ref->info_bits != 0)) {
ut_ad(ref->is_metadata());
ut_ad(ref->n_fields <= index->n_uniq);
- if (btr_pcur_open_at_index_side(
- true, index, mode, pcur, true, 0, mtr)
- != DB_SUCCESS
+ if (pcur->open_leaf(true, index, mode, mtr) != DB_SUCCESS
|| !btr_pcur_move_to_next_user_rec(pcur, mtr)) {
- return FALSE;
+ return false;
}
/* We do not necessarily have index->is_instant() here,
because we could be executing a rollback of an
@@ -1220,27 +1216,14 @@ row_search_on_row_ref(
& REC_INFO_MIN_REC_FLAG;
} else {
ut_a(ref->n_fields == index->n_uniq);
- if (btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr)
+ if (btr_pcur_open(ref, PAGE_CUR_LE, mode, pcur, 0, mtr)
!= DB_SUCCESS) {
- return FALSE;
+ return false;
}
}
- low_match = btr_pcur_get_low_match(pcur);
-
- rec = btr_pcur_get_rec(pcur);
-
- if (page_rec_is_infimum(rec)) {
-
- return(FALSE);
- }
-
- if (low_match != dtuple_get_n_fields(ref)) {
-
- return(FALSE);
- }
-
- return(TRUE);
+ return !page_rec_is_infimum(btr_pcur_get_rec(pcur))
+ && btr_pcur_get_low_match(pcur) == dtuple_get_n_fields(ref);
}
/*********************************************************************//**
@@ -1250,7 +1233,7 @@ on the secondary index record are preserved.
rec_t*
row_get_clust_rec(
/*==============*/
- ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */
const rec_t* rec, /*!< in: record in a secondary index */
dict_index_t* index, /*!< in: secondary index */
dict_index_t** clust_index,/*!< out: clustered index */
@@ -1283,9 +1266,8 @@ Searches an index record.
enum row_search_result
row_search_index_entry(
/*===================*/
- dict_index_t* index, /*!< in: index */
const dtuple_t* entry, /*!< in: index entry */
- ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */
btr_pcur_t* pcur, /*!< in/out: persistent cursor, which must
be closed by the caller */
mtr_t* mtr) /*!< in: mtr */
@@ -1296,12 +1278,12 @@ row_search_index_entry(
ut_ad(dtuple_check_typed(entry));
- if (index->is_spatial()) {
- if (rtr_pcur_open(index, entry, mode, pcur, mtr)) {
+ if (pcur->index()->is_spatial()) {
+ if (rtr_pcur_open(pcur->index(), entry, mode, pcur, mtr)) {
return ROW_NOT_FOUND;
}
} else {
- if (btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr)
+ if (btr_pcur_open(entry, PAGE_CUR_LE, mode, pcur, 0, mtr)
!= DB_SUCCESS) {
return ROW_NOT_FOUND;
}
@@ -1310,7 +1292,7 @@ row_search_index_entry(
switch (btr_pcur_get_btr_cur(pcur)->flag) {
case BTR_CUR_DELETE_REF:
ut_ad(!(~mode & BTR_DELETE));
- ut_ad(!index->is_spatial());
+ ut_ad(!pcur->index()->is_spatial());
return(ROW_NOT_DELETED_REF);
case BTR_CUR_DEL_MARK_IBUF:
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index cf1aaedf240..b13a727f59f 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -1008,17 +1008,16 @@ row_sel_get_clust_rec(
*out_rec = NULL;
- offsets = rec_get_offsets(rec,
- btr_pcur_get_btr_cur(&plan->pcur)->index,
- offsets,
- btr_pcur_get_btr_cur(&plan->pcur)->index
- ->n_core_fields, ULINT_UNDEFINED, &heap);
+ offsets = rec_get_offsets(rec, plan->pcur.index(), offsets,
+ plan->pcur.index()->n_core_fields,
+ ULINT_UNDEFINED, &heap);
row_build_row_ref_fast(plan->clust_ref, plan->clust_map, rec, offsets);
index = dict_table_get_first_index(plan->table);
-
- dberr_t err = btr_pcur_open_with_no_init(index, plan->clust_ref,
+ plan->clust_pcur.old_rec = nullptr;
+ plan->clust_pcur.btr_cur.page_cur.index = index;
+ dberr_t err = btr_pcur_open_with_no_init(plan->clust_ref,
PAGE_CUR_LE, BTR_SEARCH_LEAF,
&plan->clust_pcur, mtr);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
@@ -1410,6 +1409,9 @@ row_sel_open_pcur(
cond = UT_LIST_GET_NEXT(cond_list, cond);
}
+ plan->pcur.old_rec = nullptr;
+ plan->pcur.btr_cur.page_cur.index = index;
+
dberr_t err;
if (plan->tuple) {
@@ -1429,13 +1431,12 @@ row_sel_open_pcur(
que_node_get_val(exp));
}
- err = btr_pcur_open_with_no_init(index, plan->tuple,
+ err = btr_pcur_open_with_no_init(plan->tuple,
plan->mode, BTR_SEARCH_LEAF,
&plan->pcur, mtr);
} else {
- err = btr_pcur_open_at_index_side(plan->asc, index,
- BTR_SEARCH_LEAF, &plan->pcur,
- false, 0, mtr);
+ err = plan->pcur.open_leaf(plan->asc, index, BTR_SEARCH_LEAF,
+ mtr);
}
plan->pcur_is_open = err == DB_SUCCESS;
@@ -3370,6 +3371,7 @@ Row_sel_get_clust_rec_for_mysql::operator()(
rec_t* old_vers;
trx_t* trx;
+ prebuilt->clust_pcur->old_rec = nullptr;
*out_rec = NULL;
trx = thr_get_trx(thr);
@@ -3380,9 +3382,9 @@ Row_sel_get_clust_rec_for_mysql::operator()(
sec_index, *offsets);
clust_index = dict_table_get_first_index(sec_index->table);
+ prebuilt->clust_pcur->btr_cur.page_cur.index = clust_index;
- dberr_t err = btr_pcur_open_with_no_init(clust_index,
- prebuilt->clust_ref,
+ dberr_t err = btr_pcur_open_with_no_init(prebuilt->clust_ref,
PAGE_CUR_LE, BTR_SEARCH_LEAF,
prebuilt->clust_pcur, mtr);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
@@ -3447,9 +3449,10 @@ Row_sel_get_clust_rec_for_mysql::operator()(
rec, sec_index, true,
sec_index->n_fields, heap);
page_cur_t page_cursor;
+ page_cursor.block = block;
+ page_cursor.index = sec_index;
ulint up_match = 0, low_match = 0;
- ut_ad(!page_cur_search_with_match(block, sec_index,
- tuple, PAGE_CUR_LE,
+ ut_ad(!page_cur_search_with_match(tuple, PAGE_CUR_LE,
&up_match,
&low_match,
&page_cursor,
@@ -3639,7 +3642,8 @@ record with the same ordering prefix in in the B-tree index
@return true if we may need to process the record the cursor is now
positioned on (i.e. we should not go to the next record yet) */
static bool sel_restore_position_for_mysql(bool *same_user_rec,
- ulint latch_mode, btr_pcur_t *pcur,
+ btr_latch_mode latch_mode,
+ btr_pcur_t *pcur,
bool moves_up, mtr_t *mtr)
{
auto status = pcur->restore_position(latch_mode, mtr);
@@ -3668,7 +3672,7 @@ static bool sel_restore_position_for_mysql(bool *same_user_rec,
next:
if (btr_pcur_move_to_next(pcur, mtr)
&& rec_is_metadata(btr_pcur_get_rec(pcur),
- *pcur->btr_cur.index)) {
+ *pcur->index())) {
btr_pcur_move_to_next(pcur, mtr);
}
@@ -3684,7 +3688,7 @@ next:
prev:
if (btr_pcur_is_on_user_rec(pcur) && !moves_up
&& !rec_is_metadata(btr_pcur_get_rec(pcur),
- *pcur->btr_cur.index)) {
+ *pcur->index())) {
if (!btr_pcur_move_to_prev(pcur, mtr)) {
return true;
}
@@ -3964,8 +3968,9 @@ row_sel_try_search_shortcut_for_mysql(
ut_ad(!index->table->is_temporary());
ut_ad(!prebuilt->templ_contains_blob);
ut_ad(trx->read_view.is_open());
+ pcur->old_rec = nullptr;
- if (btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
+ if (btr_pcur_open_with_no_init(search_tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, pcur, mtr)
!= DB_SUCCESS) {
return SEL_RETRY;
@@ -4395,6 +4400,8 @@ row_search_mvcc(
DBUG_RETURN(DB_CORRUPTION);
}
+ pcur->btr_cur.page_cur.index = index;
+
/* We need to get the virtual column values stored in secondary
index key, if this is covered index scan or virtual key read is
requested. */
@@ -4766,6 +4773,7 @@ wait_table_again:
} else if (dtuple_get_n_fields(search_tuple) > 0) {
pcur->btr_cur.thr = thr;
+ pcur->old_rec = nullptr;
if (dict_index_is_spatial(index)) {
if (!prebuilt->rtr_info) {
@@ -4785,7 +4793,7 @@ wait_table_again:
}
}
- err = btr_pcur_open_with_no_init(index, search_tuple, mode,
+ err = btr_pcur_open_with_no_init(search_tuple, mode,
BTR_SEARCH_LEAF, pcur, &mtr);
if (err != DB_SUCCESS) {
@@ -4831,9 +4839,8 @@ page_corrupted:
}
}
} else if (mode == PAGE_CUR_G || mode == PAGE_CUR_L) {
- err = btr_pcur_open_at_index_side(
- mode == PAGE_CUR_G, index, BTR_SEARCH_LEAF,
- pcur, false, 0, &mtr);
+ err = pcur->open_leaf(mode == PAGE_CUR_G, index,
+ BTR_SEARCH_LEAF, &mtr);
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
@@ -5019,7 +5026,7 @@ wrong_offs:
page_cur_set_after_last(btr_pcur_get_block(pcur),
btr_pcur_get_page_cur(pcur));
- pcur->old_stored = false;
+ pcur->old_rec = nullptr;
goto next_rec;
}
}
@@ -5786,7 +5793,7 @@ next_rec_after_check:
/* This is based on btr_pcur_move_to_next() */
ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(pcur->latch_mode != BTR_NO_LATCHES);
- pcur->old_stored = false;
+ pcur->old_rec = nullptr;
if (btr_pcur_is_after_last_on_page(pcur)) {
if (btr_pcur_is_after_last_in_tree(pcur)) {
goto not_moved;
@@ -6198,8 +6205,6 @@ dberr_t row_check_index(row_prebuilt_t *prebuilt, ulint *n_rows)
*n_rows= 0;
dict_index_t *const index= prebuilt->index;
- prebuilt->fetch_direction= ROW_SEL_NEXT;
-
if (!index->is_btree())
return DB_CORRUPTION;
@@ -6210,9 +6215,8 @@ dberr_t row_check_index(row_prebuilt_t *prebuilt, ulint *n_rows)
mtr.start();
dict_index_t *clust_index= dict_table_get_first_index(prebuilt->table);
-
- dberr_t err= btr_pcur_open_at_index_side(true, index, BTR_SEARCH_LEAF,
- prebuilt->pcur, false, 0, &mtr);
+ prebuilt->clust_pcur->btr_cur.page_cur.index = clust_index;
+ dberr_t err= prebuilt->pcur->open_leaf(true, index, BTR_SEARCH_LEAF, &mtr);
if (UNIV_UNLIKELY(err != DB_SUCCESS))
{
func_exit:
@@ -6300,14 +6304,16 @@ rec_loop:
goto next_rec;
}
- if (index->is_clust())
+ if (prebuilt->table->is_temporary())
{
- if (prebuilt->trx->isolation_level == TRX_ISO_READ_UNCOMMITTED)
- {
- if (!rec_deleted)
- goto count_row;
+ count_or_not:
+ if (rec_deleted)
goto next_rec;
- }
+ }
+ else if (index->is_clust())
+ {
+ if (prebuilt->trx->isolation_level == TRX_ISO_READ_UNCOMMITTED)
+ goto count_or_not;
trx_id_t rec_trx_id= row_get_rec_trx_id(rec, index, offsets);
@@ -6371,10 +6377,7 @@ rec_loop:
ER_NOT_KEYFILE, "InnoDB: %s", w.m_oss.str().c_str());
}
- if (!rec_deleted)
- goto count_row;
-
- goto next_rec;
+ goto count_or_not;
}
else if (const trx_id_t page_trx_id= page_get_max_trx_id(page_align(rec)))
{
@@ -6388,7 +6391,7 @@ rec_loop:
const auto savepoint= mtr.get_savepoint();
row_build_row_ref_in_tuple(prebuilt->clust_ref, rec, index, offsets);
- err= btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref,
+ err= btr_pcur_open_with_no_init(prebuilt->clust_ref,
PAGE_CUR_LE, BTR_SEARCH_LEAF,
prebuilt->clust_pcur, &mtr);
if (err != DB_SUCCESS)
@@ -6887,8 +6890,7 @@ row_search_get_max_rec(
const rec_t* rec;
const bool desc = index->fields[0].descending;
- if (btr_pcur_open_at_index_side(desc, index, BTR_SEARCH_LEAF, &pcur,
- true, 0, mtr) != DB_SUCCESS) {
+ if (pcur.open_leaf(desc, index, BTR_SEARCH_LEAF, mtr) != DB_SUCCESS) {
return nullptr;
}
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index f730637c8d2..6567019a33d 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -68,7 +68,7 @@ row_undo_ins_remove_clust_rec(
dberr_t err;
ulint n_tries = 0;
mtr_t mtr;
- dict_index_t* index = node->pcur.btr_cur.index;
+ dict_index_t* index = node->pcur.index();
table_id_t table_id = 0;
const bool dict_locked = node->trx->dict_operation_lock_mode;
restart:
@@ -207,9 +207,8 @@ retry:
} else {
index->set_modified(mtr);
}
- ut_a(
- node->pcur.restore_position(BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
- &mtr) == btr_pcur_t::SAME_ALL);
+ ut_a(node->pcur.restore_position(BTR_PURGE_TREE, &mtr)
+ == btr_pcur_t::SAME_ALL);
btr_cur_pessimistic_delete(&err, FALSE, &node->pcur.btr_cur, 0, true,
&mtr);
@@ -254,7 +253,7 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_sec_low(
/*========================*/
- ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
+ btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
depending on whether we wish optimistic or
pessimistic descent down the index tree */
dict_index_t* index, /*!< in: index */
@@ -266,25 +265,27 @@ row_undo_ins_remove_sec_low(
mtr_t mtr;
const bool modify_leaf = mode == BTR_MODIFY_LEAF;
+ pcur.btr_cur.page_cur.index = index;
row_mtr_start(&mtr, index, !modify_leaf);
if (modify_leaf) {
- mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED;
+ mode = BTR_MODIFY_LEAF_ALREADY_LATCHED;
mtr_s_lock_index(index, &mtr);
} else {
- ut_ad(mode == (BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE));
+ ut_ad(mode == BTR_PURGE_TREE);
mtr_sx_lock_index(index, &mtr);
}
- if (dict_index_is_spatial(index)) {
- if (modify_leaf) {
- mode |= BTR_RTREE_DELETE_MARK;
- }
+ if (index->is_spatial()) {
+ mode = modify_leaf
+ ? btr_latch_mode(BTR_MODIFY_LEAF_ALREADY_LATCHED
+ | BTR_RTREE_DELETE_MARK
+ | BTR_RTREE_UNDO_INS)
+ : btr_latch_mode(BTR_PURGE_TREE | BTR_RTREE_UNDO_INS);
btr_pcur_get_btr_cur(&pcur)->thr = thr;
- mode |= BTR_RTREE_UNDO_INS;
}
- switch (row_search_index_entry(index, entry, mode, &pcur, &mtr)) {
+ switch (row_search_index_entry(entry, mode, &pcur, &mtr)) {
case ROW_BUFFERED:
case ROW_NOT_DELETED_REF:
/* These are invalid outcomes, because the mode passed
@@ -349,9 +350,7 @@ row_undo_ins_remove_sec(
/* Try then pessimistic descent to the B-tree */
retry:
- err = row_undo_ins_remove_sec_low(
- BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
- index, entry, thr);
+ err = row_undo_ins_remove_sec_low(BTR_PURGE_TREE, index, entry, thr);
/* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index cca44f01920..2d04dca4003 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -84,7 +84,7 @@ row_undo_mod_clust_low(
que_thr_t* thr, /*!< in: query thread */
mtr_t* mtr, /*!< in: mtr; must be committed before
latching any further pages */
- ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
+ btr_latch_mode mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
{
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
@@ -106,8 +106,8 @@ row_undo_mod_clust_low(
|| node->update->info_bits == REC_INFO_METADATA_ALTER);
if (mode != BTR_MODIFY_TREE) {
- ut_ad((mode & ulint(~BTR_ALREADY_S_LATCHED))
- == BTR_MODIFY_LEAF);
+ ut_ad(mode == BTR_MODIFY_LEAF
+ || mode == BTR_MODIFY_LEAF_ALREADY_LATCHED);
err = btr_cur_optimistic_update(
BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG
@@ -224,14 +224,14 @@ static bool row_undo_mod_must_purge(const undo_node_t &node)
ut_ad(!node.table->is_temporary());
const btr_cur_t &btr_cur= node.pcur.btr_cur;
- ut_ad(btr_cur.index->is_primary());
+ ut_ad(btr_cur.index()->is_primary());
DEBUG_SYNC_C("rollback_purge_clust");
if (!purge_sys.is_purgeable(node.new_trx_id))
return false;
const rec_t *rec= btr_cur_get_rec(&btr_cur);
- return trx_read_trx_id(rec + row_trx_id_offset(rec, btr_cur.index)) ==
+ return trx_read_trx_id(rec + row_trx_id_offset(rec, btr_cur.index())) ==
node.new_trx_id;
}
@@ -356,8 +356,7 @@ row_undo_mod_clust(
}
mtr.start();
- if (pcur->restore_position(
- BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE, &mtr) !=
+ if (pcur->restore_position(BTR_PURGE_TREE, &mtr) !=
btr_pcur_t::SAME_ALL) {
goto mtr_commit_exit;
}
@@ -483,7 +482,7 @@ row_undo_mod_del_mark_or_remove_sec_low(
que_thr_t* thr, /*!< in: query thread */
dict_index_t* index, /*!< in: index */
dtuple_t* entry, /*!< in: index entry */
- ulint mode) /*!< in: latch mode BTR_MODIFY_LEAF or
+ btr_latch_mode mode) /*!< in: latch mode BTR_MODIFY_LEAF or
BTR_MODIFY_TREE */
{
btr_pcur_t pcur;
@@ -496,15 +495,25 @@ row_undo_mod_del_mark_or_remove_sec_low(
row_mtr_start(&mtr, index, !modify_leaf);
- if (!index->is_committed()) {
+ pcur.btr_cur.page_cur.index = index;
+ btr_cur = btr_pcur_get_btr_cur(&pcur);
+
+ if (index->is_spatial()) {
+ mode = modify_leaf
+ ? btr_latch_mode(BTR_MODIFY_LEAF
+ | BTR_RTREE_DELETE_MARK
+ | BTR_RTREE_UNDO_INS)
+ : btr_latch_mode(BTR_PURGE_TREE | BTR_RTREE_UNDO_INS);
+ btr_cur->thr = thr;
+ } else if (!index->is_committed()) {
/* The index->online_status may change if the index is
or was being created online, but not committed yet. It
is protected by index->lock. */
if (modify_leaf) {
- mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED;
+ mode = BTR_MODIFY_LEAF_ALREADY_LATCHED;
mtr_s_lock_index(index, &mtr);
} else {
- ut_ad(mode == (BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE));
+ ut_ad(mode == BTR_PURGE_TREE);
mtr_sx_lock_index(index, &mtr);
}
} else {
@@ -514,18 +523,7 @@ row_undo_mod_del_mark_or_remove_sec_low(
ut_ad(!dict_index_is_online_ddl(index));
}
- btr_cur = btr_pcur_get_btr_cur(&pcur);
-
- if (dict_index_is_spatial(index)) {
- if (modify_leaf) {
- btr_cur->thr = thr;
- mode |= BTR_RTREE_DELETE_MARK;
- }
- mode |= BTR_RTREE_UNDO_INS;
- }
-
- search_result = row_search_index_entry(index, entry, mode,
- &pcur, &mtr);
+ search_result = row_search_index_entry(entry, mode, &pcur, &mtr);
switch (UNIV_EXPECT(search_result, ROW_FOUND)) {
case ROW_NOT_FOUND:
@@ -634,7 +632,7 @@ row_undo_mod_del_mark_or_remove_sec(
}
err = row_undo_mod_del_mark_or_remove_sec_low(node, thr, index,
- entry, BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE);
+ entry, BTR_PURGE_TREE);
return(err);
}
@@ -652,7 +650,7 @@ static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_mod_del_unmark_sec_and_undo_update(
/*========================================*/
- ulint mode, /*!< in: search mode: BTR_MODIFY_LEAF or
+ btr_latch_mode mode, /*!< in: search mode: BTR_MODIFY_LEAF or
BTR_MODIFY_TREE */
que_thr_t* thr, /*!< in: query thread */
dict_index_t* index, /*!< in: index */
@@ -668,8 +666,9 @@ row_undo_mod_del_unmark_sec_and_undo_update(
const ulint flags
= BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG;
row_search_result search_result;
- ulint orig_mode = mode;
+ const auto orig_mode = mode;
+ pcur.btr_cur.page_cur.index = index;
ut_ad(trx->id != 0);
if (dict_index_is_spatial(index)) {
@@ -679,7 +678,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
secondary index updates to avoid this. */
static_assert(BTR_MODIFY_TREE == (8 | BTR_MODIFY_LEAF), "");
ut_ad(!(mode & 8));
- mode |= BTR_RTREE_DELETE_MARK;
+ mode = btr_latch_mode(mode | BTR_RTREE_DELETE_MARK);
}
try_again:
@@ -687,8 +686,7 @@ try_again:
btr_cur->thr = thr;
- search_result = row_search_index_entry(index, entry, mode,
- &pcur, &mtr);
+ search_result = row_search_index_entry(entry, mode, &pcur, &mtr);
switch (search_result) {
mem_heap_t* heap;
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 26c434ca474..3b2fe849bcd 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -1840,7 +1840,7 @@ row_upd_sec_index_entry(
btr_cur_t* btr_cur;
dberr_t err = DB_SUCCESS;
trx_t* trx = thr_get_trx(thr);
- ulint mode;
+ btr_latch_mode mode;
ulint flags;
enum row_search_result search_result;
@@ -1870,14 +1870,16 @@ row_upd_sec_index_entry(
"before_row_upd_sec_index_entry");
mtr.start();
+ mode = BTR_MODIFY_LEAF;
switch (index->table->space_id) {
case SRV_TMP_SPACE_ID:
mtr.set_log_mode(MTR_LOG_NO_REDO);
flags = BTR_NO_LOCKING_FLAG;
- mode = index->is_spatial()
- ? ulint(BTR_MODIFY_LEAF | BTR_RTREE_DELETE_MARK)
- : ulint(BTR_MODIFY_LEAF);
+ if (index->is_spatial()) {
+ mode = btr_latch_mode(BTR_MODIFY_LEAF
+ | BTR_RTREE_DELETE_MARK);
+ }
break;
default:
index->set_modified(mtr);
@@ -1887,18 +1889,19 @@ row_upd_sec_index_entry(
/* We can only buffer delete-mark operations if there
are no foreign key constraints referring to the index. */
mode = index->is_spatial()
- ? ulint(BTR_MODIFY_LEAF | BTR_RTREE_DELETE_MARK)
+ ? btr_latch_mode(BTR_MODIFY_LEAF
+ | BTR_RTREE_DELETE_MARK)
: referenced
- ? ulint(BTR_MODIFY_LEAF) : ulint(BTR_DELETE_MARK_LEAF);
+ ? BTR_MODIFY_LEAF : BTR_DELETE_MARK_LEAF;
break;
}
/* Set the query thread, so that ibuf_insert_low() will be
able to invoke thd_get_trx(). */
btr_pcur_get_btr_cur(&pcur)->thr = thr;
+ pcur.btr_cur.page_cur.index = index;
- search_result = row_search_index_entry(index, entry, mode,
- &pcur, &mtr);
+ search_result = row_search_index_entry(entry, mode, &pcur, &mtr);
btr_cur = btr_pcur_get_btr_cur(&pcur);
@@ -2590,13 +2593,13 @@ row_upd_clust_step(
ut_a(pcur->rel_pos == BTR_PCUR_ON);
- ulint mode;
+ btr_latch_mode mode;
DEBUG_SYNC_C_IF_THD(trx->mysql_thd, "innodb_row_upd_clust_step_enter");
if (dict_index_is_online_ddl(index)) {
ut_ad(node->table->id != DICT_INDEXES_ID);
- mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED;
+ mode = BTR_MODIFY_LEAF_ALREADY_LATCHED;
mtr_s_lock_index(index, &mtr);
} else {
mode = BTR_MODIFY_LEAF;
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 827c02592f2..ac5fb4e33cf 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -392,9 +392,6 @@ mysql_mutex_t srv_misc_tmpfile_mutex;
/** Temporary file for miscellanous diagnostic output */
FILE* srv_misc_tmpfile;
-static ulint srv_main_thread_process_no;
-static ulint srv_main_thread_id;
-
/* The following counts are used by the srv_master_callback. */
/** Iterations of the loop bounded by 'srv_active' label. */
@@ -887,12 +884,7 @@ srv_printf_innodb_monitor(
n_reserved);
}
- fprintf(file,
- "Process ID=" ULINTPF
- ", Main thread ID=" ULINTPF
- ", state: %s\n",
- srv_main_thread_process_no,
- srv_main_thread_id,
+ fprintf(file, "Process ID=0, Main thread ID=0, state: %s\n",
srv_main_thread_op_info);
fprintf(file,
"Number of rows inserted " ULINTPF
@@ -1456,31 +1448,29 @@ static void srv_sync_log_buffer_in_background()
}
}
-/*********************************************************************//**
-This function prints progress message every 60 seconds during server
-shutdown, for any activities that master thread is pending on. */
-static
-void
-srv_shutdown_print_master_pending(
-/*==============================*/
- time_t* last_print_time, /*!< last time the function
- print the message */
- ulint n_bytes_merged) /*!< number of change buffer
- just merged */
+/** Report progress during shutdown.
+@param last time of last output
+@param n_read number of page reads initiated for change buffer merge */
+static void srv_shutdown_print(time_t &last, ulint n_read)
{
- time_t current_time = time(NULL);
-
- if (difftime(current_time, *last_print_time) > 60) {
- *last_print_time = current_time;
+ time_t now= time(nullptr);
+ if (now - last >= 15)
+ {
+ last= now;
- /* Check change buffer merge, we only wait for change buffer
- merge if it is a slow shutdown */
- if (!srv_fast_shutdown && n_bytes_merged) {
- ib::info() << "Waiting for change buffer merge to"
- " complete number of bytes of change buffer"
- " just merged: " << n_bytes_merged;
- }
- }
+ const ulint ibuf_size= ibuf.size;
+ sql_print_information("Completing change buffer merge;"
+ " %zu page reads initiated;"
+ " %zu change buffer pages remain",
+ n_read, ibuf_size);
+#if defined HAVE_SYSTEMD && !defined EMBEDDED_LIBRARY
+ service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL,
+ "Completing change buffer merge;"
+ " %zu page reads initiated;"
+ " %zu change buffer pages remain",
+ n_read, ibuf_size);
+#endif
+ }
}
/** Perform periodic tasks whenever the server is active.
@@ -1525,7 +1515,7 @@ Complete the shutdown tasks such as background DROP TABLE,
and optionally change buffer merge (on innodb_fast_shutdown=0). */
void srv_shutdown(bool ibuf_merge)
{
- ulint n_bytes_merged = 0;
+ ulint n_read = 0;
time_t now = time(NULL);
do {
@@ -1534,21 +1524,12 @@ void srv_shutdown(bool ibuf_merge)
++srv_main_shutdown_loops;
if (ibuf_merge) {
- srv_main_thread_op_info = "checking free log space";
- log_free_check();
srv_main_thread_op_info = "doing insert buffer merge";
- n_bytes_merged = ibuf_merge_all();
-
- /* Flush logs if needed */
- srv_sync_log_buffer_in_background();
- }
-
- /* Print progress message every 60 seconds during shutdown */
- if (srv_print_verbose_log) {
- srv_shutdown_print_master_pending(&now,
- n_bytes_merged);
+ log_free_check();
+ n_read = ibuf_contract();
+ srv_shutdown_print(now, n_read);
}
- } while (n_bytes_merged);
+ } while (n_read);
}
/** The periodic master task controlling the server. */
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 56bdac29694..0f471402e73 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -594,7 +594,7 @@ static dberr_t trx_resurrect_table_locks(trx_t *trx, const trx_undo_t &undo)
if (undo_block != block)
{
- mtr.memo_release(undo_block, MTR_MEMO_PAGE_S_FIX);
+ mtr.release(*undo_block);
undo_block= block;
}
trx_undo_rec_get_pars(undo_rec, &type, &cmpl_info,