oxidecomputer / oxidecomputer/omicron

[nexus] Audit transactions which may have incorrect serialization assumptions

Open
#6,694 20 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

database
Dominant language
Rust
Stars
572
Forks
97
Avg merge
2d 12h
Merged PRs (30d)
96

Description

As highlighted by https://github.com/oxidecomputer/omicron/pull/6229#discussion_r1777381312 , the following situation may be a problem with CockroachDB:

  • Interactive transaction starts, issues a SELECT for one or more rows from the database
  • The value of that row is accessed and considered, somehow
  • Concurrently, that row is modified by another operation (concurrent transaction, CTE, UPDATE, DELETE, etc).
  • The original transaction commits without updating the original row, but assuming it has not been changed.
  • No error is returned, the transaction completes "successfully", even though the assumption of immutability of that row has been violated.

In this scenario, a row was read by a transaction, and modified before the transaction committed. According to Cockroachdb's documentation, this is legal:

“CockroachDB doesn’t allow stale reads”... “No stale reads” means that, once a write transaction committed, every read transaction starting afterwards will see it.

Note that in this situation, the read transaction started before the subsequent write transaction, so the read was not considered stale. That being said, the value read by the transaction did get modified before it was committed.

This issue tracks taking a look at our usage of interactive transactions, for the following pattern:

  1. A SELECT statement is issued without a corresponding FOR UPDATE lock
  2. The result of that SELECT statement influences the rest of the transaction, in some way. Examples could be: Influencing a conditional in Rust code, using the result to populate a subsequent UPDATE or INSERT, etc.
  3. The original rows being SELECT-ed are not themselves modified by the transaction.
  4. If the transaction makes the assumption that the SELECT-ed rows must not be modified before the transaction calls COMMIT, then this is a potential problem.

An example of this issue was that highlighted within https://github.com/oxidecomputer/omicron/pull/6229, where we had roughly the following problem:

  • In a Transaction: SELECT the latest blueprint target, confirms it is equal to value X. Perform a database modification, assuming that the SELECT-ed blueprint target has not been modified.
  • Concurrently, another operation may occur, which modified the "latest target blueprint".

In this example, the following may occur:

  • Txn: SELECT the blueprint target, sees value "X"
  • Another operation modified the blueprint target to "X + 1"
  • Txn: Modify the DB, issue COMMIT. No error is observed, it is not known that the target changed mid-operation.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the discussion in PR #6229 and the repository's interactive transaction usage. Search for SELECT statements without FOR UPDATE whose results influence later transaction work while the selected rows are not modified. Done means the relevant cases have been audited and any unsafe serialization assumptions are identified and addressed.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
databases
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.