diff options
author | Annamalai Gurusami <annamalai.gurusami@oracle.com> | 2012-10-19 16:43:48 +0530 |
---|---|---|
committer | Annamalai Gurusami <annamalai.gurusami@oracle.com> | 2012-10-19 16:43:48 +0530 |
commit | 6ff71d0dd38e39e67580f598b400fa3fb8888da3 (patch) | |
tree | c424bb23f7516df547e54f927a5cf306624065b2 /sql | |
parent | 44beb951ca64a50bfd5f04626a878a138d883fe4 (diff) | |
download | mariadb-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.cc | 31 |
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 { |