summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAnnamalai Gurusami <annamalai.gurusami@oracle.com>2012-10-19 16:43:48 +0530
committerAnnamalai Gurusami <annamalai.gurusami@oracle.com>2012-10-19 16:43:48 +0530
commit6ff71d0dd38e39e67580f598b400fa3fb8888da3 (patch)
treec424bb23f7516df547e54f927a5cf306624065b2 /sql
parent44beb951ca64a50bfd5f04626a878a138d883fe4 (diff)
downloadmariadb-git-6ff71d0dd38e39e67580f598b400fa3fb8888da3.tar.gz
Bug #14226171 EXCESSIVE ROW LOCKING WITH UPDATE IN 5.5.25
When a DML statement is issued, and if the index merge access method is chosen, then many rows from the storage engine will be locked because of the way the algorithm works. Many rows will be locked, but they will not be part of the final result set. To reduce the excessive locking, the locks of unmatched rows are released by this patch. This patch will affect only transactions with isolation level equal to or less stricter than READ COMMITTED. This is because of the behaviour of ha_innobase::unlock_row(). rb://1296 approved by jorgen and olav.
Diffstat (limited to 'sql')
-rw-r--r--sql/opt_range.cc31
1 files changed, 31 insertions, 0 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index ffd66253eaa..ce87bdd5381 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -8412,6 +8412,13 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
If a Clustered PK scan is present, it is used only to check if row
satisfies its condition (and never used for row retrieval).
+ Locking: to ensure that exclusive locks are only set on records that
+ are included in the final result we must release the lock
+ on all rows we read but do not include in the final result. This
+ must be done on each index that reads the record and the lock
+ must be released using the same handler (the same quick object) as
+ used when reading the record.
+
RETURN
0 - Ok
other - Error code if any error occurred.
@@ -8421,6 +8428,12 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
{
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
QUICK_RANGE_SELECT* quick;
+
+ /* quick that reads the given rowid first. This is needed in order
+ to be able to unlock the row using the same handler object that locked
+ it */
+ QUICK_RANGE_SELECT* quick_with_last_rowid;
+
int error, cmp;
uint last_rowid_count=0;
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::get_next");
@@ -8433,7 +8446,10 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
if (cpk_quick)
{
while (!error && !cpk_quick->row_in_ranges())
+ {
+ quick->file->unlock_row(); /* row not in range; unlock */
error= quick->get_next();
+ }
}
if (error)
DBUG_RETURN(error);
@@ -8441,6 +8457,7 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
quick->file->position(quick->record);
memcpy(last_rowid, quick->file->ref, head->file->ref_length);
last_rowid_count= 1;
+ quick_with_last_rowid= quick;
while (last_rowid_count < quick_selects.elements)
{
@@ -8453,9 +8470,17 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
do
{
if ((error= quick->get_next()))
+ {
+ quick_with_last_rowid->file->unlock_row();
DBUG_RETURN(error);
+ }
quick->file->position(quick->record);
cmp= head->file->cmp_ref(quick->file->ref, last_rowid);
+ if (cmp < 0)
+ {
+ /* This row is being skipped. Release lock on it. */
+ quick->file->unlock_row();
+ }
} while (cmp < 0);
/* Ok, current select 'caught up' and returned ref >= cur_ref */
@@ -8466,13 +8491,19 @@ int QUICK_ROR_INTERSECT_SELECT::get_next()
{
while (!cpk_quick->row_in_ranges())
{
+ quick->file->unlock_row(); /* row not in range; unlock */
if ((error= quick->get_next()))
+ {
+ quick_with_last_rowid->file->unlock_row();
DBUG_RETURN(error);
+ }
}
quick->file->position(quick->record);
}
memcpy(last_rowid, quick->file->ref, head->file->ref_length);
+ quick_with_last_rowid->file->unlock_row();
last_rowid_count= 1;
+ quick_with_last_rowid= quick;
}
else
{