Retry queries on deadlock errors from InnoDB row-level locking (MySQL)

pull/121/merge
Thomas Bruederli 11 years ago
parent f806ed5c9e
commit 0ee22c2145

@ -386,17 +386,7 @@ class rcube_db
$result = $this->dbh->query($query); $result = $this->dbh->query($query);
if ($result === false) { if ($result === false) {
$error = $this->dbh->errorInfo(); $result = $this->handle_error($query);
if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') {
$this->db_error = true;
$this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
rcube::raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => $this->db_error_msg . " (SQL Query: $query)"
), true, false);
}
} }
$this->last_result = $result; $this->last_result = $result;
@ -404,6 +394,30 @@ class rcube_db
return $result; return $result;
} }
/**
* Helper method to handle DB errors.
* This by default logs the error but could be overriden by a driver implementation
*
* @param string Query that triggered the error
* @return mixed Result to be stored and returned
*/
protected function handle_error($query)
{
$error = $this->dbh->errorInfo();
if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') {
$this->db_error = true;
$this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
rcube::raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => $this->db_error_msg . " (SQL Query: $query)"
), true, false);
}
return false;
}
/** /**
* Get number of affected rows for the last query * Get number of affected rows for the last query
* *

@ -179,4 +179,29 @@ class rcube_db_mysql extends rcube_db
return isset($this->variables[$varname]) ? $this->variables[$varname] : $default; return isset($this->variables[$varname]) ? $this->variables[$varname] : $default;
} }
/**
* Handle DB errors, re-issue the query on deadlock errors from InnoDB row-level locking
*
* @param string Query that triggered the error
* @return mixed Result to be stored and returned
*/
protected function handle_error($query)
{
$error = $this->dbh->errorInfo();
// retry after "Deadlock found when trying to get lock" errors
$retries = 2;
while ($error[1] == 1213 && $retries >= 0) {
usleep(50000); // wait 50 ms
$result = $this->dbh->query($query);
if ($result !== false) {
return $result;
}
$error = $this->dbh->errorInfo();
$retries--;
}
return parent::handle_error($query);
}
} }

Loading…
Cancel
Save