Fix Race Condition

Posted . Visible to the public.

Fix At Adapter Level

// app\code\core\Mage\CatalogInventory\Model\Resource\Stock.php    
/**
 * Correct particular stock products qty based on operator
 *
 * @param Mage_CatalogInventory_Model_Stock $stock
 * @param array $productQtys
 * @param string $operator +/-
 * @return $this
 */
public function correctItemsQty($stock, $productQtys, $operator = '-')
{
    if (empty($productQtys)) {
        return $this;
    }

    $adapter = $this->_getWriteAdapter();
    $conditions = array();
    foreach ($productQtys as $productId => $qty) {
        $case = $adapter->quoteInto('?', $productId);
        $result = $adapter->quoteInto("qty{$operator}?", $qty);
        $conditions[$case] = $result;
    }

    $value = $adapter->getCaseSql('product_id', $conditions, 'qty');

    $where = array(
        'product_id IN (?)' => array_keys($productQtys),
        'stock_id = ?'      => $stock->getId()
    );

    $adapter->beginTransaction();
    try {
        $adapter->update($this->getTable('cataloginventory/stock_item'), array('qty' => $value), $where);
        $adapter->commit();
    } catch (Exception $e) {
        $adapter->rollBack();
        throw $e;
    }

    return $this;
}

Fix at Model Level

/**
 * Fix race condition.
 * Note: $write->insertOnDuplicate() or $write->update() at adapter level doesn't work.
 *
 * @param Sxx_AccountPayment_Model_Ledger $ledger
 * @return float
 * @throws Exception
 */
protected function _fetchNewBalance(Sxx_AccountPayment_Model_Ledger $ledger)
{
    // Start transaction to run SELECT ... FOR UPDATE
    $this->beginTransaction();

    try {
        /** @var Sxx_AccountPayment_Model_Ledger_Balance $model */
        $model = Mage::getModel('accountpayment/ledger_balance');
        $model->loadByOwnerLedger($ledger->getData('owner_id'), $ledger->getData('name'));
        if (!$model->getId()) {
            $model->setData(
                [
                    'owner_id' => $ledger->getData('owner_id'),
                    'name' => $ledger->getData('name'),
                    'balance' => $ledger->getLastEntry()->getData('balance')
                ]
            );
            $model->save();
        }

        $balance = $model->getData('balance') + $ledger->getData('amount');
        $model->setData('balance', $balance);
        $model->save();

        $this->commit();
    } catch (Exception $e) {
        $this->rollBack();
        throw $e;
    }

    return $balance;
}
kiatng
Last edit
kiatng
Tags
Posted by kiatng to OpenMage (2021-01-22 01:34)