Merge from mysql-5.1-innodb:

------------------------------------------------------------
revno: 3495
committer: Marko Mäkelä <marko.makela@oracle.com>
branch nick: 5.1-innodb
timestamp: Wed 2010-06-02 13:37:14 +0300
message:
  Bug#53674: InnoDB: Error: unlock row could not find a 4 mode lock on the record

  In semi-consistent read, only unlock freshly locked non-matching records.

  lock_rec_lock_fast(): Return LOCK_REC_SUCCESS,
  LOCK_REC_SUCCESS_CREATED, or LOCK_REC_FAIL instead of TRUE/FALSE.

  enum db_err: Add DB_SUCCESS_LOCKED_REC for indicating a successful
  operation where a record lock was created.

  lock_sec_rec_read_check_and_lock(),
  lock_clust_rec_read_check_and_lock(), lock_rec_enqueue_waiting(),
  lock_rec_lock_slow(), lock_rec_lock(), row_ins_set_shared_rec_lock(),
  row_ins_set_exclusive_rec_lock(), sel_set_rec_lock(),
  row_sel_get_clust_rec_for_mysql(): Return DB_SUCCESS_LOCKED_REC if a
  new record lock was created. Adjust callers.

  row_unlock_for_mysql(): Correct the function documentation.

  row_prebuilt_t::new_rec_locks: Correct the documentation.
This commit is contained in:
Marko Mäkelä 2010-06-02 14:37:33 +03:00
commit a2b9532188
10 changed files with 308 additions and 211 deletions

View file

@ -1121,9 +1121,9 @@ nonstandard_exit_func:
/*********************************************************************//**
Sets a shared lock on a record. Used in locking possible duplicate key
records and also in checking foreign key constraints.
@return DB_SUCCESS or error code */
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
static
ulint
enum db_err
row_ins_set_shared_rec_lock(
/*========================*/
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
@ -1134,7 +1134,7 @@ row_ins_set_shared_rec_lock(
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
que_thr_t* thr) /*!< in: query thread */
{
ulint err;
enum db_err err;
ut_ad(rec_offs_validate(rec, index, offsets));
@ -1152,9 +1152,9 @@ row_ins_set_shared_rec_lock(
/*********************************************************************//**
Sets a exclusive lock on a record. Used in locking possible duplicate key
records
@return DB_SUCCESS or error code */
@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */
static
ulint
enum db_err
row_ins_set_exclusive_rec_lock(
/*===========================*/
ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or
@ -1165,7 +1165,7 @@ row_ins_set_exclusive_rec_lock(
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
que_thr_t* thr) /*!< in: query thread */
{
ulint err;
enum db_err err;
ut_ad(rec_offs_validate(rec, index, offsets));
@ -1205,7 +1205,6 @@ row_ins_check_foreign_constraint(
dict_index_t* check_index;
ulint n_fields_cmp;
btr_pcur_t pcur;
ibool moved;
int cmp;
ulint err;
ulint i;
@ -1336,13 +1335,13 @@ run_again:
/* Scan index records and check if there is a matching record */
for (;;) {
do {
const rec_t* rec = btr_pcur_get_rec(&pcur);
const buf_block_t* block = btr_pcur_get_block(&pcur);
if (page_rec_is_infimum(rec)) {
goto next_rec;
continue;
}
offsets = rec_get_offsets(rec, check_index,
@ -1353,12 +1352,13 @@ run_again:
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block,
rec, check_index,
offsets, thr);
if (err != DB_SUCCESS) {
break;
switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
continue;
default:
goto end_scan;
}
goto next_rec;
}
cmp = cmp_dtuple_rec(entry, rec, offsets);
@ -1369,9 +1369,12 @@ run_again:
err = row_ins_set_shared_rec_lock(
LOCK_ORDINARY, block,
rec, check_index, offsets, thr);
if (err != DB_SUCCESS) {
switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto end_scan;
}
} else {
/* Found a matching record. Lock only
@ -1382,15 +1385,18 @@ run_again:
LOCK_REC_NOT_GAP, block,
rec, check_index, offsets, thr);
if (err != DB_SUCCESS) {
switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto end_scan;
}
if (check_ref) {
err = DB_SUCCESS;
break;
goto end_scan;
} else if (foreign->type != 0) {
/* There is an ON UPDATE or ON DELETE
condition: check them in a separate
@ -1416,7 +1422,7 @@ run_again:
err = DB_FOREIGN_DUPLICATE_KEY;
}
break;
goto end_scan;
}
/* row_ins_foreign_check_on_constraint
@ -1429,49 +1435,41 @@ run_again:
thr, foreign, rec, entry);
err = DB_ROW_IS_REFERENCED;
break;
goto end_scan;
}
}
}
} else {
ut_a(cmp < 0);
if (cmp < 0) {
err = row_ins_set_shared_rec_lock(
LOCK_GAP, block,
rec, check_index, offsets, thr);
if (err != DB_SUCCESS) {
break;
switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
if (check_ref) {
err = DB_NO_REFERENCED_ROW;
row_ins_foreign_report_add_err(
trx, foreign, rec, entry);
} else {
err = DB_SUCCESS;
}
}
if (check_ref) {
err = DB_NO_REFERENCED_ROW;
row_ins_foreign_report_add_err(
trx, foreign, rec, entry);
} else {
err = DB_SUCCESS;
}
break;
goto end_scan;
}
} while (btr_pcur_move_to_next(&pcur, &mtr));
ut_a(cmp == 0);
next_rec:
moved = btr_pcur_move_to_next(&pcur, &mtr);
if (!moved) {
if (check_ref) {
rec = btr_pcur_get_rec(&pcur);
row_ins_foreign_report_add_err(
trx, foreign, rec, entry);
err = DB_NO_REFERENCED_ROW;
} else {
err = DB_SUCCESS;
}
break;
}
if (check_ref) {
row_ins_foreign_report_add_err(
trx, foreign, btr_pcur_get_rec(&pcur), entry);
err = DB_NO_REFERENCED_ROW;
} else {
err = DB_SUCCESS;
}
end_scan:
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@ -1719,9 +1717,13 @@ row_ins_scan_sec_index_for_duplicate(
rec, index, offsets, thr);
}
if (err != DB_SUCCESS) {
switch (err) {
case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
case DB_SUCCESS:
break;
default:
goto end_scan;
}
if (page_rec_is_supremum(rec)) {
@ -1738,17 +1740,15 @@ row_ins_scan_sec_index_for_duplicate(
thr_get_trx(thr)->error_info = index;
break;
goto end_scan;
}
} else {
ut_a(cmp < 0);
goto end_scan;
}
if (cmp < 0) {
break;
}
ut_a(cmp == 0);
} while (btr_pcur_move_to_next(&pcur, &mtr));
end_scan:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@ -1837,7 +1837,11 @@ row_ins_duplicate_error_in_clust(
cursor->index, offsets, thr);
}
if (err != DB_SUCCESS) {
switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto func_exit;
}
@ -1877,7 +1881,11 @@ row_ins_duplicate_error_in_clust(
rec, cursor->index, offsets, thr);
}
if (err != DB_SUCCESS) {
switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default:
goto func_exit;
}