Project

General

Profile

Bug #24342 » t3lib_class.t3lib_lock.php.patch

Administrator Admin, 2010-12-15 13:15

View differences:

t3lib/class.t3lib_lock.php (working copy)
* @subpackage t3lib
* @see class.t3lib_tstemplate.php, class.tslib_fe.php
*/
class t3lib_lock {
class t3lib_abstract_lock {
protected $method;
protected $id; // Identifier used for this lock
protected $resource; // Resource used for this lock (can be a file or a semaphore resource)
protected $filepointer;
protected $isAcquired = FALSE;
protected $destruct=FALSE; // destroy all resources on destruct
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.
......
* @return void
*/
function __destruct() {
$this->destruct=TRUE;
$this->release();
}
......
* @return boolean Returns true if lock could be acquired without waiting, false otherwise.
*/
public function acquire() {
$this->isAcquired = FALSE;
return FALSE;
}
/**
* Release the lock
*
* @return boolean Returns TRUE on success or FALSE on failure
*/
public function release() {
return TRUE;
}
/**
* Return the locking method which is currently used
*
* @return string Locking method
*/
public function getMethod() {
return $this->method;
}
/**
* Return the ID which is currently used
*
* @return string Locking ID
*/
public function getId() {
return $this->id;
}
/**
* Return the resource which is currently used.
* Depending on the locking method this can be a filename or a semaphore resource.
*
* @return mixed Locking resource (filename as string or semaphore as resource)
*/
public function getResource() {
return $this->resource;
}
/**
* Return the status of a lock
*
* @return string Returns TRUE if lock is acquired, FALSE otherwise
*/
public function getLockStatus() {
return $this->isAcquired;
}
/**
* Adds a common log entry for this locking API using t3lib_div::sysLog().
* Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired
*
* @param string $message: The message to be logged
* @param integer $severity: Severity - 0 is info (default), 1 is notice, 2 is warning, 3 is error, 4 is fatal error
* @return void
*/
public function sysLog($message, $severity = 0) {
t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), 'cms', $severity);
}
}
/**
* a static lock class used for the lock file lock
* The lock ressource is not removed in case of release (except simple locking)
* the stale lock time-out is increased
*
* @author pedersen
*
*/
class t3lib_lock_static extends t3lib_abstract_lock {
/**
* Constructor:
* initializes locking, check input parameters and set variables accordingly.
*
* @param string ID to identify this lock in the system
* @param string Define which locking method to use. Defaults to "simple".
* @param integer Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method.
* @param integer 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.
* @return boolean Returns true unless something went wrong
*/
public function __construct($id, $method = '', $loops = 0, $step = 0) {
$res=parent::__construct($id,$method,$loops,$step);
parent::sysLog("Static semaphore " . $this->id);
return $res;
}
/**
* Acquire a lock and return when successful. If the lock is already open, the client will be
*
* It is important to know that the lock will be acquired in any case, even if the request was blocked first. Therefore, the lock needs to be released in every situation.
*
* @return boolean Returns true if lock could be acquired without waiting, false otherwise.
*/
public function acquire() {
$noWait = TRUE; // Default is TRUE, which means continue without caring for other clients. In the case of TYPO3s cache management, this has no negative effect except some resource overhead.
$isAcquired = TRUE;
......
if (is_file($this->resource)) {
$this->sysLog('Waiting for a different process to release the lock');
$maxExecutionTime = ini_get('max_execution_time');
$maxAge = time() - ($maxExecutionTime ? $maxExecutionTime : 120);
$maxAge = time() - 3*($maxExecutionTime ? $maxExecutionTime : 120);
if (@filectime($this->resource) < $maxAge) {
@unlink($this->resource);
$this->sysLog('Unlink stale lockfile');
......
$filepointer = @fopen($this->resource, 'x');
if ($filepointer !== FALSE) {
fclose($filepointer);
$this->sysLog('Lock aquired');
$this->sysLog('Lock acquired');
$noWait = ($i === 0);
$isAcquired = TRUE;
break;
......
}
break;
case 'semaphore':
$this->sysLog('Static semaphore ' . $this->id );
if (sem_acquire($this->resource)) {
$this->sysLog('Static semaphore ' . $this->id );
// Unfortunately it seems not possible to find out if the request was blocked, so we return FALSE in any case to make sure the operation is tried again.
$noWait = FALSE;
}
......
* @return boolean Returns TRUE on success or FALSE on failure
*/
public function release() {
if (!$this->isAcquired) {
$this->sysLog('Release static semaphore ' . $this->id );
if (!$this->isAcquired&& !$this->destruct) {
return TRUE;
}
......
$success = FALSE;
}
fclose($this->filepointer);
unlink($this->resource);
break;
case 'semaphore':
$this->sysLog('Release static semaphore ' . $this->id );
if (@sem_release($this->resource)) {
sem_remove($this->resource);
} else {
$success = FALSE;
}
......
return $success;
}
}
class t3lib_lock extends t3lib_abstract_lock {
/**
* Return the locking method which is currently used
* Constructor:
* initializes locking, check input parameters and set variables accordingly.
*
* @return string Locking method
* @param string ID to identify this lock in the system
* @param string Define which locking method to use. Defaults to "simple".
* @param integer Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method.
* @param integer 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.
* @return boolean Returns true unless something went wrong
*/
public function getMethod() {
return $this->method;
public function __construct($id, $method = '', $loops = 0, $step = 0) {
parent::__construct($id,$method,$loops,$step);
$this->initLockLock($method,$loops,$step);
}
public function initLockLock($method,$loops,$step) {
if (!$GLOBALS['lockLock'] || !($GLOBALS['lockLock'] instanceof t3lib_lock_static)) {
$GLOBALS['lockLock']=t3lib_div::makeInstance('t3lib_lock_static','lockLock',$method,$loops,$step);
}
}
/**
* Return the ID which is currently used
* Acquire a lock and return when successful. If the lock is already open, the client will be
*
* @return string Locking ID
* It is important to know that the lock will be acquired in any case, even if the request was blocked first. Therefore, the lock needs to be released in every situation.
*
* @return boolean Returns true if lock could be acquired without waiting, false otherwise.
*/
public function getId() {
return $this->id;
public function acquire() {
$noWait = TRUE; // Default is TRUE, which means continue without caring for other clients. In the case of TYPO3s cache management, this has no negative effect except some resource overhead.
$isAcquired = TRUE;
switch ($this->method) {
case 'simple':
if (is_file($this->resource)) {
$this->sysLog('Waiting for a different process to release the lock');
$maxExecutionTime = ini_get('max_execution_time');
$maxAge = time() - ($maxExecutionTime ? $maxExecutionTime : 120);
if ($GLOBALS['lockLock']->acquire() || $GLOBALS['lockLock']->getLockStatus()){
if (@filectime($this->resource) < $maxAge) {
@unlink($this->resource);
$this->sysLog('Unlink stale lockfile');
}
}
$GLOBALS['lockLock']->release();
}
$isAcquired = FALSE;
for ($i = 0; $i < $this->loops; $i++) {
$filepointer = @fopen($this->resource, 'x');
if ($filepointer !== FALSE) {
fclose($filepointer);
$this->sysLog('Lock acquired');
$noWait = ($i === 0);
$isAcquired = TRUE;
break;
}
usleep($this->step * 1000);
}
if (!$isAcquired) {
throw new Exception('Lock file could not be created');
}
break;
case 'flock':
if (($this->filepointer = fopen($this->resource, 'w+')) == FALSE) {
throw new Exception('Lock file could not be opened');
}
if (flock($this->filepointer, LOCK_EX | LOCK_NB) == TRUE) { // Lock without blocking
$noWait = TRUE;
} elseif (flock($this->filepointer, LOCK_EX) == TRUE) { // Lock with blocking (waiting for similar locks to become released)
$noWait = FALSE;
} else {
throw new Exception('Could not lock file "' . $this->resource . '"');
}
break;
case 'semaphore':
$this->sysLog('Acquire semaphore ' . $this->id );
if (sem_acquire($this->resource)) {
// Unfortunately it seems not possible to find out if the request was blocked, so we return FALSE in any case to make sure the operation is tried again.
$noWait = FALSE;
}
break;
case 'disable':
$noWait = FALSE;
$isAcquired = FALSE;
break;
}
$this->isAcquired = $isAcquired;
return $noWait;
}
/**
* Return the resource which is currently used.
* Depending on the locking method this can be a filename or a semaphore resource.
* Release the lock
*
* @return mixed Locking resource (filename as string or semaphore as resource)
* @return boolean Returns TRUE on success or FALSE on failure
*/
public function getResource() {
return $this->resource;
}
public function release() {
if (!$this->isAcquired&& !$this->destruct) {
return TRUE;
}
/**
* Return the status of a lock
*
* @return string Returns TRUE if lock is acquired, FALSE otherwise
*/
public function getLockStatus() {
return $this->isAcquired;
$success = TRUE;
if ($GLOBALS['lockLock']->acquire() || $GLOBALS['lockLock']->getLockStatus()){
switch ($this->method) {
case 'simple':
if (unlink($this->resource) == FALSE) {
$success = FALSE;
}
break;
case 'flock':
if (flock($this->filepointer, LOCK_UN) == FALSE) {
$success = FALSE;
}
fclose($this->filepointer);
unlink($this->resource);
break;
case 'semaphore':
if (@sem_release($this->resource)) {
sem_remove($this->resource);
} else {
$success = FALSE;
}
break;
case 'disable':
$success = FALSE;
break;
}
}
$GLOBALS['lockLock']->release();
$this->isAcquired = FALSE;
return $success;
}
/**
* Adds a common log entry for this locking API using t3lib_div::sysLog().
* Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired
*
* @param string $message: The message to be logged
* @param integer $severity: Severity - 0 is info (default), 1 is notice, 2 is warning, 3 is error, 4 is fatal error
* @return void
*/
public function sysLog($message, $severity = 0) {
t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), 'cms', $severity);
}
}
(1-1/4)