dsn); $database = $dsnArray['database']; $domainID = CRM_Core_Config::domainID(); if ($serverWideLock) { $this->_name = $name; } else { $this->_name = $database . '.' . $domainID . '.' . $name; } if (defined('CIVICRM_LOCK_DEBUG')) { CRM_Core_Error::debug_log_message('trying to construct lock for ' . $this->_name); } $this->_timeout = $timeout !== NULL ? $timeout : self::TIMEOUT; } public function __destruct() { $this->release(); } /** * @return bool */ public function acquire($timeout = NULL) { if (!$this->_hasLock) { if (self::$jobLog && CRM_Core_DAO::singleValueQuery("SELECT IS_USED_LOCK( '" . self::$jobLog . "')")) { return $this->hackyHandleBrokenCode(self::$jobLog); } $query = "SELECT GET_LOCK( %1, %2 )"; $params = array( 1 => array($this->_name, 'String'), 2 => array($timeout ? $timeout : $this->_timeout, 'Integer'), ); $res = CRM_Core_DAO::singleValueQuery($query, $params); if ($res) { if (defined('CIVICRM_LOCK_DEBUG')) { CRM_Core_Error::debug_log_message('acquire lock for ' . $this->_name); } $this->_hasLock = TRUE; if (stristr($this->_name, 'data.mailing.job.')) { self::$jobLog = $this->_name; } } else { if (defined('CIVICRM_LOCK_DEBUG')) { CRM_Core_Error::debug_log_message('failed to acquire lock for ' . $this->_name); } } } return $this->_hasLock; } /** * @return null|string */ public function release() { if ($this->_hasLock) { if (defined('CIVICRM_LOCK_DEBUG')) { CRM_Core_Error::debug_log_message('release lock for ' . $this->_name); } $this->_hasLock = FALSE; if (self::$jobLog == $this->_name) { self::$jobLog = FALSE; } $query = "SELECT RELEASE_LOCK( %1 )"; $params = array(1 => array($this->_name, 'String')); return CRM_Core_DAO::singleValueQuery($query, $params); } } /** * @return null|string */ public function isFree() { $query = "SELECT IS_FREE_LOCK( %1 )"; $params = array(1 => array($this->_name, 'String')); return CRM_Core_DAO::singleValueQuery($query, $params); } /** * @return bool */ public function isAcquired() { return $this->_hasLock; } /** * CRM-12856 locks were originally set up for jobs, but the concept was extended to caching & groups without * understanding that would undermine the job locks (because grabbing a lock implicitly releases existing ones) * this is all a big hack to mitigate the impact of that - but should not be seen as a fix. Not sure correct fix * but maybe locks should be used more selectively? Or else we need to handle is some cool way that Tim is yet to write :-) * if we are running in the context of the cron log then we would rather die (or at least let our process die) * than release that lock - so if the attempt is being made by setCache or something relatively trivial * we'll just return TRUE, but if it's another job then we will crash as that seems 'safer' * * @param string $jobLog * @throws CRM_Core_Exception * @return bool */ public function hackyHandleBrokenCode($jobLog) { if (stristr($this->_name, 'job')) { CRM_Core_Error::debug_log_message('lock acquisition for ' . $this->_name . ' attempted when ' . $jobLog . ' is not released'); throw new CRM_Core_Exception('lock acquisition for ' . $this->_name . ' attempted when ' . $jobLog . ' is not released'); } if (defined('CIVICRM_LOCK_DEBUG')) { CRM_Core_Error::debug_log_message('(CRM-12856) faking lock for ' . $this->_name); } $this->_hasLock = TRUE; return TRUE; } }