mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 03:23:03 +01:00
Restart requests in case of update conflicts
This commit is contained in:
parent
fad46cfe90
commit
c3500bb843
@ -8062,7 +8062,28 @@ void JRD_start(Jrd::thread_db* tdbb, jrd_req* request, jrd_tra* transaction)
|
||||
*
|
||||
**************************************/
|
||||
EXE_unwind(tdbb, request);
|
||||
EXE_start(tdbb, request, transaction);
|
||||
|
||||
// Repeat execution to handle update conflicts, if any
|
||||
int numTries = 0;
|
||||
while (true) {
|
||||
try {
|
||||
EXE_start(tdbb, request, transaction);
|
||||
break;
|
||||
} catch (const status_exception &ex) {
|
||||
const ISC_STATUS* v = ex.value();
|
||||
if ((transaction->tra_flags & TRA_read_committed) &&
|
||||
v[0] == isc_arg_gds &&
|
||||
v[1] == isc_update_conflict)
|
||||
{
|
||||
if (++numTries < 10) {
|
||||
fb_utils::init_status(tdbb->tdbb_status_vector);
|
||||
EXE_unwind(tdbb, request);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
check_autocommit(tdbb, request);
|
||||
|
||||
@ -8152,8 +8173,29 @@ void JRD_start_and_send(thread_db* tdbb, jrd_req* request, jrd_tra* transaction,
|
||||
*
|
||||
**************************************/
|
||||
EXE_unwind(tdbb, request);
|
||||
EXE_start(tdbb, request, transaction);
|
||||
EXE_send(tdbb, request, msg_type, msg_length, msg);
|
||||
|
||||
// Repeat execution to handle update conflicts, if any
|
||||
int numTries = 0;
|
||||
while (true) {
|
||||
try {
|
||||
EXE_start(tdbb, request, transaction);
|
||||
EXE_send(tdbb, request, msg_type, msg_length, msg);
|
||||
break;
|
||||
} catch (const status_exception &ex) {
|
||||
const ISC_STATUS* v = ex.value();
|
||||
if ((transaction->tra_flags & TRA_read_committed) &&
|
||||
v[0] == isc_arg_gds &&
|
||||
v[1] == isc_update_conflict)
|
||||
{
|
||||
if (++numTries < 10) {
|
||||
fb_utils::init_status(tdbb->tdbb_status_vector);
|
||||
EXE_unwind(tdbb, request);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
check_autocommit(tdbb, request);
|
||||
|
||||
|
@ -1909,7 +1909,7 @@ void TRA_sweep(thread_db* tdbb)
|
||||
}
|
||||
|
||||
|
||||
int TRA_wait(thread_db* tdbb, jrd_tra* trans, TraNumber number, jrd_tra::wait_t wait)
|
||||
int TRA_wait(thread_db* tdbb, jrd_tra* trans, TraNumber number, jrd_tra::wait_t wait, bool* deadlock_flag)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1944,6 +1944,9 @@ int TRA_wait(thread_db* tdbb, jrd_tra* trans, TraNumber number, jrd_tra::wait_t
|
||||
|
||||
if (!LCK_lock(tdbb, &temp_lock, LCK_read, timeout))
|
||||
{
|
||||
if (deadlock_flag)
|
||||
*deadlock_flag = tdbb->tdbb_status_vector->getErrors()[1] == isc_deadlock;
|
||||
|
||||
fb_utils::init_status(tdbb->tdbb_status_vector);
|
||||
return tra_active;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ Jrd::jrd_tra* TRA_start(Jrd::thread_db* tdbb, int, const UCHAR*, Jrd::jrd_tra* o
|
||||
int TRA_state(const UCHAR*, TraNumber oldest, TraNumber number);
|
||||
void TRA_sweep(Jrd::thread_db* tdbb);
|
||||
void TRA_update_counters(Jrd::thread_db*, Jrd::Database*);
|
||||
int TRA_wait(Jrd::thread_db* tdbb, Jrd::jrd_tra* trans, TraNumber number, Jrd::jrd_tra::wait_t wait);
|
||||
int TRA_wait(Jrd::thread_db* tdbb, Jrd::jrd_tra* trans, TraNumber number, Jrd::jrd_tra::wait_t wait, bool* deadlock_flag = NULL);
|
||||
void TRA_attach_request(Jrd::jrd_tra* transaction, Jrd::jrd_req* request);
|
||||
void TRA_detach_request(Jrd::jrd_req* request);
|
||||
void TRA_setup_request_snapshot(Jrd::thread_db*, Jrd::jrd_req* request);
|
||||
|
@ -158,6 +158,7 @@ const int PREPARE_OK = 0;
|
||||
const int PREPARE_CONFLICT = 1;
|
||||
const int PREPARE_DELETE = 2;
|
||||
const int PREPARE_LOCKERR = 3;
|
||||
const int PREPARE_DEADLOCK = 4;
|
||||
|
||||
static int prepare_update(thread_db*, jrd_tra*, TraNumber commit_tid_read, record_param*,
|
||||
record_param*, record_param*, PageStack&, bool);
|
||||
@ -262,12 +263,12 @@ inline void check_gbak_cheating_delete(thread_db* tdbb, const jrd_rel* relation)
|
||||
}
|
||||
}
|
||||
|
||||
inline int wait(thread_db* tdbb, jrd_tra* transaction, const record_param* rpb)
|
||||
inline int wait(thread_db* tdbb, jrd_tra* transaction, const record_param* rpb, bool* deadlock_flag = NULL)
|
||||
{
|
||||
if (transaction->getLockWait())
|
||||
tdbb->bumpRelStats(RuntimeStatistics::RECORD_WAITS, rpb->rpb_relation->rel_id);
|
||||
|
||||
return TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait);
|
||||
return TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait, deadlock_flag);
|
||||
}
|
||||
|
||||
inline bool checkGCActive(thread_db* tdbb, record_param* rpb, int& state)
|
||||
@ -840,7 +841,8 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb,
|
||||
// of a dead record version.
|
||||
|
||||
CCH_RELEASE(tdbb, &rpb->getWindow(tdbb));
|
||||
state = wait(tdbb, transaction, rpb);
|
||||
bool deadlock_flag;
|
||||
state = wait(tdbb, transaction, rpb, &deadlock_flag);
|
||||
|
||||
if (state == tra_precommitted)
|
||||
state = check_precommitted(transaction, rpb);
|
||||
@ -849,9 +851,13 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb,
|
||||
{
|
||||
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id);
|
||||
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_read_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(rpb->rpb_transaction_nr));
|
||||
if (deadlock_flag)
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_read_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(rpb->rpb_transaction_nr));
|
||||
else
|
||||
ERR_post(Arg::Gds(isc_read_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(rpb->rpb_transaction_nr));
|
||||
}
|
||||
|
||||
// refetch the record and try again. The active transaction
|
||||
@ -1872,11 +1878,16 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
|
||||
{
|
||||
// Update stub didn't find one page -- do a long, hard update
|
||||
PageStack stack;
|
||||
if (prepare_update(tdbb, transaction, tid_fetch, rpb, &temp, 0, stack, false))
|
||||
int error_code;
|
||||
if ((error_code = prepare_update(tdbb, transaction, tid_fetch, rpb, &temp, 0, stack, false)))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(rpb->rpb_transaction_nr));
|
||||
if (error_code == PREPARE_DEADLOCK)
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(rpb->rpb_transaction_nr));
|
||||
else
|
||||
ERR_post(Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(rpb->rpb_transaction_nr));
|
||||
}
|
||||
|
||||
// Old record was restored and re-fetched for write. Now replace it.
|
||||
@ -3148,12 +3159,17 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
|
||||
const bool backVersion = (org_rpb->rpb_b_page != 0);
|
||||
record_param temp;
|
||||
PageStack stack;
|
||||
if (prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, org_rpb, &temp, new_rpb,
|
||||
stack, false))
|
||||
int error_code;
|
||||
if ((error_code = prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, org_rpb, &temp, new_rpb,
|
||||
stack, false)))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(org_rpb->rpb_transaction_nr));
|
||||
if (error_code == PREPARE_DEADLOCK)
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(org_rpb->rpb_transaction_nr));
|
||||
else
|
||||
ERR_post(Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(org_rpb->rpb_transaction_nr));
|
||||
}
|
||||
|
||||
IDX_modify_flag_uk_modified(tdbb, org_rpb, new_rpb, transaction);
|
||||
@ -3385,8 +3401,7 @@ bool VIO_refetch_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction
|
||||
{
|
||||
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, rpb->rpb_relation->rel_id);
|
||||
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_update_conflict) <<
|
||||
ERR_post(Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(rpb->rpb_transaction_nr));
|
||||
}
|
||||
|
||||
@ -4005,9 +4020,9 @@ bool VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* transaction)
|
||||
org_rpb->rpb_runtime_flags |= RPB_refetch;
|
||||
return false;
|
||||
case PREPARE_LOCKERR:
|
||||
// We got some kind of locking error (deadlock, timeout or lock_conflict)
|
||||
// Error details should be stuffed into status vector at this point
|
||||
// hvlad: we have no details as TRA_wait has already cleared the status vector
|
||||
ERR_post(Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(org_rpb->rpb_transaction_nr));
|
||||
case PREPARE_DEADLOCK:
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(org_rpb->rpb_transaction_nr));
|
||||
@ -5679,7 +5694,8 @@ static int prepare_update( thread_db* tdbb,
|
||||
// Wait as long as it takes for an active transaction which has modified
|
||||
// the record.
|
||||
|
||||
state = wait(tdbb, transaction, rpb);
|
||||
bool deadlock_flag;
|
||||
state = wait(tdbb, transaction, rpb, &deadlock_flag);
|
||||
|
||||
if (state == tra_precommitted)
|
||||
state = check_precommitted(transaction, rpb);
|
||||
@ -5712,8 +5728,7 @@ static int prepare_update( thread_db* tdbb,
|
||||
{
|
||||
tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id);
|
||||
|
||||
ERR_post(Arg::Gds(isc_deadlock) <<
|
||||
Arg::Gds(isc_update_conflict) <<
|
||||
ERR_post(Arg::Gds(isc_update_conflict) <<
|
||||
Arg::Gds(isc_concurrent_transaction) << Arg::Num(update_conflict_trans));
|
||||
}
|
||||
|
||||
@ -5723,7 +5738,7 @@ static int prepare_update( thread_db* tdbb,
|
||||
// fall thru
|
||||
|
||||
case tra_active:
|
||||
return PREPARE_LOCKERR;
|
||||
return deadlock_flag ? PREPARE_DEADLOCK : PREPARE_LOCKERR;
|
||||
|
||||
case tra_dead:
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user