Index: t3lib/stddb/tables.sql =================================================================== --- t3lib/stddb/tables.sql (Revision 8246) +++ t3lib/stddb/tables.sql (Arbeitskopie) @@ -413,6 +413,15 @@ ) ENGINE=InnoDB; # +# Table structure for table 'sys_lock' +# +CREATE TABLE sys_lock ( + id varchar(64) DEFAULT '' NOT NULL, + expires int(11) unsigned DEFAULT '0' NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB; + +# # Table structure for table 'sys_language' # CREATE TABLE sys_language ( Index: t3lib/class.t3lib_lock.php =================================================================== --- t3lib/class.t3lib_lock.php (Revision 8246) +++ t3lib/class.t3lib_lock.php (Arbeitskopie) @@ -59,6 +59,12 @@ * @see class.t3lib_tstemplate.php, class.tslib_fe.php */ class t3lib_lock { + const METHOD_SIMPLE = 'simple'; + const METHOD_FLOCK = 'flock'; + const METHOD_SEMAPHORE = 'semaphore'; + const METHOD_DATABASE = 'database'; + const METHOD_DISABLE = 'disable'; + protected $method; protected $id; // Identifier used for this lock protected $resource; // Resource used for this lock (can be a file or a semaphore resource) @@ -67,6 +73,7 @@ protected $loops = 150; // Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method. protected $step = 200; // Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used by manual locks like the "simple" method. + protected $expiration = 300; // Number of seconds after a resource shall expire @@ -94,7 +101,7 @@ } // Detect locking method - if (in_array($method, array('disable', 'simple', 'flock', 'semaphore'))) { + if (in_array($method, array('disable', 'simple', 'flock', 'semaphore', 'database'))) { $this->method = $method; } else { throw new Exception('No such method "' . $method . '"'); @@ -118,6 +125,11 @@ $success = TRUE; } break; + case 'database': + $this->id = sha1($id); + $this->resource = $GLOBALS['TYPO3_DB']->fullQuoteStr($this->id, 'sys_lock'); + $success = TRUE; + break; case 'disable': return FALSE; break; @@ -150,6 +162,7 @@ switch ($this->method) { case 'simple': if (is_file($this->resource)) { + $noWait = FALSE; $this->sysLog('Waiting for a different process to release the lock'); $i = 0; while ($i<$this->loops) { @@ -158,7 +171,6 @@ clearstatcache(); if (!is_file($this->resource)) { // Lock became free, leave the loop $this->sysLog('Different process released the lock'); - $noWait = FALSE; break; } } @@ -189,6 +201,32 @@ $noWait = FALSE; } break; + case 'database': + $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_lock', 'expires<' . $GLOBALS['EXEC_TIME']); + $noWait = FALSE; + + while ($i < $this->loops) { + if ($this->isDatabaseLockActive()) { + $i++; + usleep($this->step * 1000); + } else { + $noWait = TRUE; + break; + } + } + + $fields = array( + 'expires' => $GLOBALS['EXEC_TIME'] + $this->expiration, + 'id' => $this->id, + ); + + if ($noWait || !$this->isDatabaseLockActive()) { + $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_lock', $fields); + } else { + $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_lock', 'id=' . $this->resource, $fields); + } + + break; case 'disable': $noWait = FALSE; $isAcquired = FALSE; @@ -230,6 +268,9 @@ $success = FALSE; } break; + case 'database': + $GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_lock', 'id=' . $this->resource); + $success = ($GLOBALS['TYPO3_DB']->sql_affected_rows() > 0); case 'disable': $success = FALSE; break; @@ -287,6 +328,15 @@ public function sysLog($message, $severity=0) { t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id.']: ' . trim($message), 'cms', $severity); } + + /** + * Determines whether a database lock is active. + * + * @return boolean + */ + protected function isDatabaseLockActive() { + return ($GLOBALS['TYPO3_DB']->exec_SELECTcountRows('id', 'sys_lock', 'id=' . $this->resource) != 0); + } }