Skip to content

Recover deadlock on a cursor move - #6035

Open
dorinhogea wants to merge 1 commit into
bloomberg:mainfrom
dorinhogea:recovdlock
Open

Recover deadlock on a cursor move#6035
dorinhogea wants to merge 1 commit into
bloomberg:mainfrom
dorinhogea:recovdlock

Conversation

@dorinhogea

@dorinhogea dorinhogea commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Extend lock release to non-snapshot transactional modes, by caching the data cursors associated with index cursors before lock release.

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Error ⚠.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
sc_repeated_updates
sc_repeated_updates_logicalsc_generated
yast_stat4scan_generated
yast
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
selectv_rcode_serialretry_generated
selectv_rcode_serialize_reads_like_writes_generated
selectv_rcode_force_commit_generated

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Error ⚠.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
sc_truncate_multiddl_generated [db unavailable at finish] **quarantined**
scindex_logicalsc_generated
sc_repeated_updates_logicalsc_generated
sc_repeated_updates
recover_deadlock
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**
selectv_rcode_serialretry_generated

@dorinhogea
dorinhogea force-pushed the recovdlock branch 2 times, most recently from 16cf7a2 to 8d0ffb1 Compare July 31, 2026 16:40

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Error ⚠.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
scindex
sc_repeated_updates
recover_deadlock
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**
selectv_rcode_serialretry_generated
selectv_rcode_serialize_reads_like_writes_generated
selectv_rcode_force_commit_generated

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Error ⚠.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
scindex_logicalsc_generated
scindex
sc_resume_logicalsc_generated **quarantined**
sc_repeated_updates
recom_replay
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**
selectv_rcode_serialretry_generated

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Success ✓.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
sc_repeated_updates
recom_replay
reco-ddlk-sql **quarantined**
noresetgen
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**
selectv_rcode_serialretry_generated
selectv_rcode_serialize_reads_like_writes_generated
selectv_rcode_force_commit_generated

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Success ✓.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
sc_truncate_multiddl_generated [db unavailable at finish] **quarantined**
scindex_logicalsc_generated
scindex
sc_resume_logicalsc_generated **quarantined**
sc_repeated_updates
cdb2jdbc
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**

@dorinhogea
dorinhogea force-pushed the recovdlock branch 3 times, most recently from 68a881f to 7baaba1 Compare August 11, 2026 15:35

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Error ⚠.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
tablelocks [failed with core dumped]
sc_repeated_updates
sc_repeated_updates_logicalsc_generated
cdb2jdbc
recom_replay
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**
sql_logfill_autodisable

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Error ⚠.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_drop [failed with core dumped]
scindex_logicalsc_generated
scindex
sc_resume
sc_repeated_updates
sc_repeated_updates_logicalsc_generated
cdb2jdbc
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**

A non-snapshot read on a non-covering index defers the data lookup
(OP_DeferredSeek); if cursor_move_postop releases locks for a waiting rep
thread and a concurrent DELETE commits, the later seek loses the race
("Dta lookup lost the race").

Before releasing, sync_index_data_cursors pre-fetches each index cursor's
paired data cursor into its buffer so the deferred seek reads the captured
row.  sync reads the cursor's live bdb genid (postop runs before pCur->genid
is updated) to also cover the just-entered row, and stores bytes via
cursor_stash_found_buf() which copies into owned buffers instead of aliasing
them (aliasing double-freed the shared buffer at close).

A concurrent DROP can free a table's dbtable/schema out from under a cursor
during the release window -- on a replicant, scdone_drop/delete_table_rep
frees them without waiting for local readers.  cursor_check_table_valid()
re-resolves the table from the thread's rootpage map (safe even after a drop)
and compares the live schema object against the cursor's cached one, without
ever dereferencing the possibly-freed dbtable.  Used in the recover_deadlock
reposition loop and in the deferred-seek fast path, both of which previously
could hand back data read through a dangling pCur->sc.  A plain rebuild only
swaps the bdb handle, leaving the schema object unchanged, so it is
distinguished from a real ALTER/drop, which replaces it.
sqlite3BtreeGetTblName() is also fixed to resolve names the same way, since it
is called from failure paths that can run after the same drop.

Gated by recover_deadlock_sync_dta (default on).  Adds tests/recovdlock.test
covering the inner-loop, entered-row, and concurrent-DROP scenarios.

Signed-off-by: Dorin Hogea <dhogea@bloomberg.net>

@roborivers roborivers left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cbuild submission: Success ✓.
Regression testing: Success ✓.

The first 10 failing tests are:
sc_truncate_multiddl_generated [db unavailable at finish] **quarantined**
scindex
scindex_logicalsc_generated
sc_repeated_updates
sc_repeated_updates_logicalsc_generated
cdb2jdbc
recover_deadlock
reco-ddlk-sql **quarantined**
analyze_partial_index_off_generated **quarantined**
analyze **quarantined**

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants