| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Concurrency\LockBackend; |
|
|
| use Piwik\Common; |
| use Piwik\Concurrency\LockBackend; |
| use Piwik\Db; |
|
|
| class MySqlLockBackend implements LockBackend |
| { |
| public const TABLE_NAME = 'locks'; |
|
|
| |
| |
| |
| public function getKeysMatchingPattern($pattern) |
| { |
| $sql = sprintf('SELECT SQL_NO_CACHE distinct `key` FROM `%s` WHERE `key` like ? and %s', self::getTableName(), $this->getQueryPartExpiryTime()); |
| $pattern = str_replace('*', '%', $pattern); |
| $keys = Db::fetchAll($sql, array($pattern)); |
| $raw = array_column($keys, 'key'); |
| return $raw; |
| } |
|
|
| public function setIfNotExists($key, $value, $ttlInSeconds) |
| { |
| if (empty($ttlInSeconds)) { |
| $ttlInSeconds = 999999999; |
| } |
|
|
| |
| |
| |
| |
| |
| |
|
|
| if ($this->get($key)) { |
| return false; |
| } |
|
|
| $tablePrefixed = self::getTableName(); |
|
|
| |
| |
| if ($this->keyExists($key)) { |
| |
| |
| $sql = sprintf('DELETE FROM `%s` WHERE `key` = ? and not (%s)', $tablePrefixed, $this->getQueryPartExpiryTime()); |
| Db::query($sql, array($key)); |
| } |
|
|
| $query = sprintf( |
| 'INSERT INTO `%s` (`key`, `value`, `expiry_time`) |
| VALUES (?,?,(UNIX_TIMESTAMP() + ?))', |
| $tablePrefixed |
| ); |
| |
|
|
| try { |
| Db::query($query, array($key, $value, (int) $ttlInSeconds)); |
| } catch (\Exception $e) { |
| if ( |
| $e->getCode() == 23000 |
| || strpos($e->getMessage(), 'Duplicate entry') !== false |
| || strpos($e->getMessage(), ' 1062 ') !== false |
| ) { |
| return false; |
| } |
| throw $e; |
| } |
|
|
| |
| return $this->get($key) === $value; |
| } |
|
|
| public function get($key) |
| { |
| $sql = sprintf('SELECT SQL_NO_CACHE `value` FROM `%s` WHERE `key` = ? AND %s LIMIT 1', self::getTableName(), $this->getQueryPartExpiryTime()); |
| return Db::fetchOne($sql, array($key)); |
| } |
|
|
| public function deleteIfKeyHasValue($key, $value) |
| { |
| if (empty($value)) { |
| return false; |
| } |
|
|
| $sql = sprintf('DELETE FROM `%s` WHERE `key` = ? and `value` = ?', self::getTableName()); |
| return $this->queryDidMakeChange($sql, array($key, $value)); |
| } |
|
|
| public function expireIfKeyHasValue($key, $value, $ttlInSeconds) |
| { |
| if (empty($value)) { |
| return false; |
| } |
|
|
| |
| |
| $sql = sprintf('UPDATE `%s` SET expiry_time = (UNIX_TIMESTAMP() + ?) WHERE `key` = ? and `value` = ?', self::getTableName()); |
| $success = $this->queryDidMakeChange($sql, array((int) $ttlInSeconds, $key, $value)); |
|
|
| if (!$success) { |
| |
| |
| return $value === $this->get($key); |
| } |
|
|
| return true; |
| } |
|
|
| public function keyExists($key) |
| { |
| $sql = sprintf('SELECT SQL_NO_CACHE 1 FROM `%s` WHERE `key` = ? LIMIT 1', self::getTableName()); |
| $value = Db::fetchOne($sql, array($key)); |
| return !empty($value); |
| } |
|
|
| private function queryDidMakeChange($sql, $bind = array()) |
| { |
| $query = Db::query($sql, $bind); |
| if (is_object($query) && method_exists($query, 'rowCount')) { |
| |
| return (bool) $query->rowCount(); |
| } else { |
| |
| return (bool) Db::get()->rowCount($query); |
| } |
| } |
|
|
| private static function getTableName() |
| { |
| return Common::prefixTable(self::TABLE_NAME); |
| } |
|
|
| private function getQueryPartExpiryTime() |
| { |
| return 'UNIX_TIMESTAMP() <= expiry_time'; |
| } |
| } |
|
|