Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

DB layer 2.0 delegated transactions

From MoodleDocs

Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the page comments.

Moodle 2.0


General principles

  1. Everybody thinks it's a good idea to have those logical nested transactions in Moodle (but me and ML)
  2. No matter of they nested nature, they are really "delegated transactions" (so outer levels get the control over inner ones), so we are going to apply that naming to enforce the real concept.
  3. Code will never rely on rollback happening. it's only a maeasure to reduce (not to eliminate) DB garbled information.
  4. Any problem related with the use of transactions (unfinished ones, unbalanced, finished twice...) will end always with one transaction_exception that will always end performing one DB rollback.
  5. If one transaction (at any level) has been marked for rollback() there won't be any method to change it. Finally Moodle will perform the DB rollback.
  6. If one transaction (at any level) has been marked for commit() it will be possible to change that status to rollback() in any outer level.
  7. It will be optional to catch exceptions when using transactions, but if they are caught, then it's mandatory to mark the transaction for rollback()
  8. Any explicit rollback() call will pass the exception originating it, i.e. rollback($exception) to be re-thrown.
  9. API will work in a natural and similar fashion to current recordsets one.
  10. We'll start recommending to use InnoDB for 2.0 in environmental tests. Posibly, at some point in the future that will become a must. But it is not for now (be warned!).

The API

  1. All the handling must go, exclusively, to moodle_database object, leaving real drivers only implementing (protected) the old begin/commit/rollback_sql() functions.
  2. One array of objects of type moodle_delegated_transaction will be stored / checked from $DB
  3. $DB will be the responsible to instantiate / accumulate / pair / compare moodle_delegated_transactions
  4. Each moodle_transaction will be able to set the global mark for rollback. Commit won't change anything.
  5. Inner-most commit/rollback will printout one complete stack of moodle_transactions information if we are under DEBUG_DEVELOPER and new setting (delegatedtransactionsdebug) is enabled.
  6. Normal usage of the moodle_transaction will be:
$transaction = $DB->start_delegated_transaction();
// Perform some $DB stuff
$transaction->allow_commit();

7. If, for any reason, developer needs to catch exceptions when using transactions, it will be mandatory to use it in this way:

try {
    $transaction = $DB->start_delegated_transaction();
    // Perform some $DB stuff
    $transaction->allow_commit();
} catch (Exception $e) {
    //extra cleanup steps
    $transaction->rollback($e); // rethrows exception
}

8. In order to be able to keep some parts of code out from top transactions completely, if we know it can lead to problems, we can use:

 $DB->transactions_forbidden(); // Instant check to confirm we aren't using transactions in this point. Will throw exception if transaction is found.

The Flow

caption
  1. Any default exception handler will:
    1. Catch uncaught transaction_exception exceptions,
    2. Properly perform the DB rollback
    3. debug/error/log honouring related settings.
    4. inform with as many details as possible (token, place... whatever).
  2. Any "footer" (meaning some place before ending <html> output) will:
    1. Detect "in-transaction" status.
    2. Let execution continue, transaction is automatically rolled back in $DB->dispose()
    3. inform with as many details as possible (token, place... whatever).
  3. $DB->dispose() will:
    1. Detect "in-transaction" status.
    2. log error (not possible to honour settings!)
    3. Properly perform the full DB rollback

Related tasks

  1. Move this to MoodleDocs and publicy in Dev Forum.
  2. Implement fulfilling current specs / review / test iterations
  3. Re-enforce in Docs, phpdocs, everywhere, the "Code will *never* rely on rollback happening" and the "delegated" nature of the whole thing.
  4. Be extremely careful about any use of delegated transactions until we get used to them, reviewing them in core often.
  5. Point somewhere about the move to InnoDB, pros/cons, migration process... to have it documented.