Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Missing "Lock wait timeout exceeded" handling in magento's pdo_mysql adapter?

If i compare the two Magento adapter classes Varien_Db_Adapter_Mysqli and Varien_Db_Adapter_Pdo_Mysql i can find some differences in the query exception handling of method raw_query.

<?php

class Varien_Db_Adapter_Mysqli extends Zend_Db_Adapter_Mysqli
{

//....

/**
 * Run RAW Query
 *
 * @param string $sql
 * @return Zend_Db_Statement_Interface
 */
public function raw_query($sql)
{
    $timeoutMessage = 'SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded;      try restarting transaction';
    $tries = 0;
    do {
        $retry = false;
        try {
            $this->clear_result();
            $result = $this->getConnection()->query($sql);
            $this->clear_result();
        } catch (Exception $e) {
            if ($tries < 10 && $e->getMessage() == $timeoutMessage) {
                $retry = true;
                $tries++;
            } else {
                throw $e;
            }
        }
    } while ($retry);

    return $result;
}

//....

}

If i compare this with equal method in Varien_Db_Adapter_Pdo_Mysql i find another error handling. It checks not for timeouts, but for lost connections.

<?php

class Varien_Db_Adapter_Pdo_Mysql  extends Zend_Db_Adapter_Pdo_Mysql implements Varien_Db_Adapter_Interface
{

//....


/**
 * Run RAW Query
 *
 * @param string $sql
 * @return Zend_Db_Statement_Interface
 * @throws PDOException
 */
public function raw_query($sql)
{
    $lostConnectionMessage = 'SQLSTATE[HY000]: General error: 2013 Lost connection to MySQL server during query';
    $tries = 0;
    do {
        $retry = false;
        try {
            $result = $this->query($sql);
        } catch (Exception $e) {
            // Convert to PDOException to maintain backwards compatibility with usage of MySQL adapter
            if ($e instanceof Zend_Db_Statement_Exception) {
                $e = $e->getPrevious();
                if (!($e instanceof PDOException)) {
                    $e = new PDOException($e->getMessage(), $e->getCode());
                }
            }
            // Check to reconnect
            if ($tries < 10 && $e->getMessage() == $lostConnectionMessage) {
                $retry = true;
                $tries++;
            } else {
                throw $e;
            }
        }
    } while ($retry);

    return $result;
}

//....

}

Is that correct? Would it not be better to check both failure cases?

Example:

/**
 * Run RAW Query
 *
 * @param string $sql
 * @return Zend_Db_Statement_Interface
 * @throws PDOException
 */
public function raw_query($sql)
{
    $lostConnectionMessages = array(
        'SQLSTATE[HY000]: General error: 2013 Lost connection to MySQL server during query',
        'SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction',
    );
    $tries = 0;
    do {
        $retry = false;
        try {
            $result = $this->query($sql);
        } catch (Exception $e) {
            // Convert to PDOException to maintain backwards compatibility with usage of MySQL adapter
            if ($e instanceof Zend_Db_Statement_Exception) {
                $e = $e->getPrevious();
                if (!($e instanceof PDOException)) {
                    $e = new PDOException($e->getMessage(), $e->getCode());
                }
            }
            // Check to reconnect
            if ($tries < 10 && in_array($e->getMessage(), $lostConnectionMessages)) {
                $retry = true;
                $tries++;
            } else {
                throw $e;
            }
        }
    } while ($retry);

    return $result;
}
like image 209
cmuench Avatar asked Jul 06 '12 16:07

cmuench


2 Answers

I would say, yes, they should check this also. In Magento2 they removed even the lost-connection reconnect, but in the MysqlI adapter it is still there.

like image 111
Alex Avatar answered Oct 29 '22 07:10

Alex


It depends (always a good answer :)

I think a lost connection should be considered a bug in the system setup. The way Varien_Db_Adapter_Pdo_Mysql works around it hides the origin of slow query times. I would rather see the real exception then have Magento try and reestablish the connection automatically.

The same could be said for the lock wait timeout. I want to know if such timeouts occur. Masking them with automatic retries might make errors "go away", but without fixing the real issues.

Such automatic recovery code should be at least be configurable through some option in the system configuration, for example "Enable DB query recovery mode" or something like that, and default to "disabled".

like image 39
Vinai Avatar answered Oct 29 '22 07:10

Vinai