Jump to:
| Project: | Drupal Commerce |
| Version: | 7.x-1.x-dev |
| Component: | Commerce |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | active |
Issue Summary
In the DrupalCommerceEntityController::buildQuery() method:
<?php
if (isset($this->entityInfo['locking mode']) && $this->entityInfo['locking mode'] == 'pessimistic') {
// In pessimistic locking mode, we issue the load query with a FOR UPDATE
// clause. This will block all other load queries to the loaded objects
// but requires us to start a transaction.
if (empty($this->controllerTransaction)) {
$this->controllerTransaction = db_transaction();
}
$query->forUpdate();
// Store the ids of the entities in the lockedEntities array for later
// tracking, flipped for easier management via unset() below.
$this->lockedEntities += array_flip($ids);
}
?>This also happens when loading entities, DrupalDefaultEntityController::load():
<?php
// Load any remaining entities from the database. This is the case if $ids
// is set to FALSE (so we load all entities), if there are any ids left to
// load, if loading a revision, or if $conditions was passed without $ids.
if ($ids === FALSE || $ids || $revision_id || ($conditions && !$passed_ids)) {
// Build the query.
$query = $this->buildQuery($ids, $conditions, $revision_id);
$queried_entities = $query
->execute()
->fetchAllAssoc($this->idKey);
}
?>Which then directly returns the entities:
<?php
return $entities;
?>The transaction is never commited because of this: $this->controllerTransaction.
Each time someone loads an entity via a commerce controller, the full page rendering will happen in one unique giant database transaction, with a FOR UPDATE row locking! This may explain some slowness of Commerce.
I experienced it doing heavy import jobs, the first load attempt using any commerce controller will put a transaction right at the beginning and never be released (commit). I was injecting 3000+ line items into 300+ orders, in my case, this doesn't slow things that much because I currently have only one parallel thread on my development box, the horrible side effect is that I cannot watch what's happening for debug purposes while injecting my stuff: I need to be able wether or not I need a transaction, and if I need one, I will place it in my business code myself.
Comments
#1
Correction: it's only doing this for orders, still happens potentially since the cart is itself an order (I didn't tested it thought).
#2
Other correction: the giant transaction will happen only if the order is not saved (which happens most of the case).
#3
Other correction: I surely understand why the pessimistic locking serve the Commerce framework here, but by the roleplay of various concurrent modules (rules, migrate, views, etc...) you may end up locking a lock of orders in a lot of threads, pretty much all the time: there is probably a way to avoid this in some cases.