From 0404a607a569bf9797b79dd9fb74832789de9479 Mon Sep 17 00:00:00 2001
From: unknown <marko@hundin.mysql.fi>
Date: Fri, 10 Dec 2004 12:55:56 +0200
Subject: [PATCH] InnoDB: Reduce the stack space consumption of ON UPDATE
 CASCADE operations.

innobase/include/lock0lock.h:
  Added lock_clust_rec_read_check_and_lock_alt(),
  a variant of lock_clust_rec_read_check_and_lock()
  without the parameter "offsets".
innobase/lock/lock0lock.c:
  Added lock_clust_rec_read_check_and_lock_alt(),
  a variant of lock_clust_rec_read_check_and_lock()
  without the parameter "offsets".
innobase/row/row0ins.c:
  row_ins_foreign_check_on_constraint(): Do not allocate offsets
  from stack. This reduces the stack space consumption of
  ON UPDATE CASCADE operations by 400 bytes per cascaded UPDATE
  operation.
---
 innobase/include/lock0lock.h | 27 +++++++++++++++++++++++
 innobase/lock/lock0lock.c    | 42 ++++++++++++++++++++++++++++++++++++
 innobase/row/row0ins.c       |  8 ++-----
 3 files changed, 71 insertions(+), 6 deletions(-)

diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h
index b99359fe99..e533ac0854 100644
--- a/innobase/include/lock0lock.h
+++ b/innobase/include/lock0lock.h
@@ -345,6 +345,33 @@ lock_clust_rec_read_check_and_lock(
 				LOCK_REC_NOT_GAP */
 	que_thr_t*	thr);	/* in: query thread */
 /*************************************************************************
+Checks if locks of other transactions prevent an immediate read, or passing
+over by a read cursor, of a clustered index record. If they do, first tests
+if the query thread should anyway be suspended for some reason; if not, then
+puts the transaction and the query thread to the lock wait state and inserts a
+waiting request for a record lock to the lock queue. Sets the requested mode
+lock on the record. This is an alternative version of
+lock_clust_rec_read_check_and_lock() that does not require the parameter
+"offsets". */
+
+ulint
+lock_clust_rec_read_check_and_lock_alt(
+/*===================================*/
+				/* out: DB_SUCCESS, DB_LOCK_WAIT,
+				DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
+	ulint		flags,	/* in: if BTR_NO_LOCKING_FLAG bit is set,
+				does nothing */
+	rec_t*		rec,	/* in: user record or page supremum record
+				which should be read or passed over by a read
+				cursor */
+	dict_index_t*	index,	/* in: clustered index */
+	ulint		mode,	/* in: mode of the lock which the read cursor
+				should set on records: LOCK_S or LOCK_X; the
+				latter is possible in SELECT FOR UPDATE */
+	ulint		gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
+				LOCK_REC_NOT_GAP */
+	que_thr_t*	thr);	/* in: query thread */
+/*************************************************************************
 Checks that a record is seen in a consistent read. */
 
 ibool
diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c
index 961210dbd0..7007501938 100644
--- a/innobase/lock/lock0lock.c
+++ b/innobase/lock/lock0lock.c
@@ -5105,3 +5105,45 @@ lock_clust_rec_read_check_and_lock(
 
 	return(err);
 }
+/*************************************************************************
+Checks if locks of other transactions prevent an immediate read, or passing
+over by a read cursor, of a clustered index record. If they do, first tests
+if the query thread should anyway be suspended for some reason; if not, then
+puts the transaction and the query thread to the lock wait state and inserts a
+waiting request for a record lock to the lock queue. Sets the requested mode
+lock on the record. This is an alternative version of
+lock_clust_rec_read_check_and_lock() that does not require the parameter
+"offsets". */
+
+ulint
+lock_clust_rec_read_check_and_lock_alt(
+/*===================================*/
+				/* out: DB_SUCCESS, DB_LOCK_WAIT,
+				DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
+	ulint		flags,	/* in: if BTR_NO_LOCKING_FLAG bit is set,
+				does nothing */
+	rec_t*		rec,	/* in: user record or page supremum record
+				which should be read or passed over by a read
+				cursor */
+	dict_index_t*	index,	/* in: clustered index */
+	ulint		mode,	/* in: mode of the lock which the read cursor
+				should set on records: LOCK_S or LOCK_X; the
+				latter is possible in SELECT FOR UPDATE */
+	ulint		gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
+				LOCK_REC_NOT_GAP */
+	que_thr_t*	thr)	/* in: query thread */
+{
+	mem_heap_t*	tmp_heap	= NULL;
+	ulint		offsets_[100]	= { 100, };
+	ulint*		offsets		= offsets_;
+	ulint		ret;
+
+	offsets = rec_get_offsets(rec, index, offsets,
+						ULINT_UNDEFINED, &tmp_heap);
+	ret = lock_clust_rec_read_check_and_lock(flags, rec, index,
+						offsets, mode, gap_mode, thr);
+	if (tmp_heap) {
+		mem_heap_free(tmp_heap);
+	}
+	return(ret);
+}
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 969c3341be..8b19f9d9a1 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -717,8 +717,6 @@ row_ins_foreign_check_on_constraint(
 	ulint		i;
 	trx_t*		trx;
 	mem_heap_t*	tmp_heap	= NULL;
-	ulint		offsets_[100]	= { 100, };
-	ulint*		offsets		= offsets_;
 
 	ut_a(thr && foreign && pcur && mtr);
 
@@ -886,10 +884,8 @@ row_ins_foreign_check_on_constraint(
 		we already have a normal shared lock on the appropriate
 		gap if the search criterion was not unique */
 
-		offsets = rec_get_offsets(clust_rec, clust_index, offsets,
-						ULINT_UNDEFINED, &tmp_heap);
-		err = lock_clust_rec_read_check_and_lock(0, clust_rec,
-			clust_index, offsets, LOCK_X, LOCK_REC_NOT_GAP, thr);
+		err = lock_clust_rec_read_check_and_lock_alt(0, clust_rec,
+			clust_index, LOCK_X, LOCK_REC_NOT_GAP, thr);
 	}
 	
 	if (err != DB_SUCCESS) {
-- 
2.30.9