diff --git a/inc/anti-bot.php b/inc/anti-bot.php index d41be3e0..f21b6d5f 100644 --- a/inc/anti-bot.php +++ b/inc/anti-bot.php @@ -201,26 +201,44 @@ function _create_antibot($board, $thread) { purge_old_antispam(); } - // Keep the now invalid timestamps around for a bit to enable users to post if they're still on an old version of - // the HTML page. - // By virtue of existing, we know that we're making a new version of the page, and the user from now on may just reload. - if ($thread) - $query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL'); - else - $query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` IS NULL AND `expires` IS NULL'); + retry_on_deadlock(4, function() use($thread, $board, $config) { + // Keep the now invalid timestamps around for a bit to enable users to post if they're still on an old version of + // the HTML page. + // By virtue of existing, we know that we're making a new version of the page, and the user from now on may just reload. + if ($thread) { + $query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL'); + } else { + $query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` IS NULL AND `expires` IS NULL'); + } - $query->bindValue(':board', $board); - if ($thread) - $query->bindValue(':thread', $thread); - $query->bindValue(':expires', $config['spam']['hidden_inputs_expire']); - $query->execute() or error(db_error($query)); + $query->bindValue(':board', $board); + if ($thread) { + $query->bindValue(':thread', $thread); + } + $query->bindValue(':expires', $config['spam']['hidden_inputs_expire']); + // Throws on error. + $query->execute(); + }); - // Insert an antispam with infinite life as the HTML page of a thread might last well beyond the expiry date. - $query = prepare('INSERT INTO ``antispam`` VALUES (:board, :thread, :hash, UNIX_TIMESTAMP(), NULL, 0)'); - $query->bindValue(':board', $board); - $query->bindValue(':thread', $thread); - $query->bindValue(':hash', $antibot->hash()); - $query->execute() or error(db_error($query)); + try { + $hash = $antibot->hash(); + + retry_on_deadlock(2, function() use($board, $thread, $hash) { + // Insert an antispam with infinite life as the HTML page of a thread might last well beyond the expiry date. + $query = prepare('INSERT INTO ``antispam`` VALUES (:board, :thread, :hash, UNIX_TIMESTAMP(), NULL, 0)'); + $query->bindValue(':board', $board); + $query->bindValue(':thread', $thread); + $query->bindValue(':hash', $hash); + // Throws on error. + $query->execute(); + }); + } catch(\PDOException $e) { + if ($e->errorInfo === null || $e->errorInfo[1] != MYSQL_ER_LOCK_DEADLOCK) { + throw $e; + } else { + error_log('Multiple deadlocks on _create_antibot while inserting, skipping'); + } + } return $antibot; }