|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2008-2011 Michael Stucki (michael@typo3.org) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 /** 00028 * Class for providing locking features in TYPO3 00029 * 00030 * $Id: class.t3lib_lock.php 10297 2011-01-25 10:17:36Z baschny $ 00031 * 00032 * @author Michael Stucki <michael@typo3.org> 00033 */ 00034 00035 00036 /** 00037 * TYPO3 locking class 00038 * This class provides an abstract layer to various locking features for TYPO3 00039 * 00040 * It is intended to blocks requests until some data has been generated. 00041 * This is especially useful if two clients are requesting the same website short after each other. While the request of client 1 triggers building and caching of the website, client 2 will be waiting at this lock. 00042 * 00043 * @author Michael Stucki <michael@typo3.org> 00044 * @package TYPO3 00045 * @subpackage t3lib 00046 * @see class.t3lib_tstemplate.php, class.tslib_fe.php 00047 */ 00048 class t3lib_lock { 00049 protected $method; 00050 protected $id; // Identifier used for this lock 00051 protected $resource; // Resource used for this lock (can be a file or a semaphore resource) 00052 protected $filepointer; 00053 protected $isAcquired = FALSE; 00054 00055 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. 00056 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. 00057 protected $syslogFacility = 'cms'; 00058 protected $isLoggingEnabled = TRUE; 00059 00060 00061 /** 00062 * Constructor: 00063 * initializes locking, check input parameters and set variables accordingly. 00064 * 00065 * @param string ID to identify this lock in the system 00066 * @param string Define which locking method to use. Defaults to "simple". 00067 * @param integer Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method. 00068 * @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. 00069 * @return boolean Returns true unless something went wrong 00070 */ 00071 public function __construct($id, $method = '', $loops = 0, $step = 0) { 00072 00073 // Input checks 00074 $id = (string) $id; // Force ID to be string 00075 if (intval($loops)) { 00076 $this->loops = intval($loops); 00077 } 00078 if (intval($step)) { 00079 $this->step = intval($step); 00080 } 00081 00082 // Detect locking method 00083 if (in_array($method, array('disable', 'simple', 'flock', 'semaphore'))) { 00084 $this->method = $method; 00085 } else { 00086 throw new Exception('No such method "' . $method . '"'); 00087 } 00088 00089 $success = FALSE; 00090 switch ($this->method) { 00091 case 'simple': 00092 case 'flock': 00093 $path = PATH_site . 'typo3temp/locks/'; 00094 if (!is_dir($path)) { 00095 t3lib_div::mkdir($path); 00096 } 00097 $this->id = md5($id); 00098 $this->resource = $path . $this->id; 00099 $success = TRUE; 00100 break; 00101 case 'semaphore': 00102 $this->id = abs(crc32($id)); 00103 if (($this->resource = sem_get($this->id, 1)) == TRUE) { 00104 $success = TRUE; 00105 } 00106 break; 00107 case 'disable': 00108 return FALSE; 00109 break; 00110 } 00111 00112 return $success; 00113 } 00114 00115 /** 00116 * Destructor: 00117 * Releases lock automatically when instance is destroyed. 00118 * 00119 * @return void 00120 */ 00121 function __destruct() { 00122 $this->release(); 00123 } 00124 00125 /** 00126 * Acquire a lock and return when successful. If the lock is already open, the client will be 00127 * 00128 * 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. 00129 * 00130 * @return boolean Returns true if lock could be acquired without waiting, false otherwise. 00131 */ 00132 public function acquire() { 00133 $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. 00134 $isAcquired = TRUE; 00135 00136 switch ($this->method) { 00137 case 'simple': 00138 if (is_file($this->resource)) { 00139 $this->sysLog('Waiting for a different process to release the lock'); 00140 $maxExecutionTime = ini_get('max_execution_time'); 00141 $maxAge = time() - ($maxExecutionTime ? $maxExecutionTime : 120); 00142 if (@filectime($this->resource) < $maxAge) { 00143 @unlink($this->resource); 00144 $this->sysLog('Unlink stale lockfile'); 00145 } 00146 } 00147 00148 $isAcquired = FALSE; 00149 for ($i = 0; $i < $this->loops; $i++) { 00150 $filepointer = @fopen($this->resource, 'x'); 00151 if ($filepointer !== FALSE) { 00152 fclose($filepointer); 00153 $this->sysLog('Lock aquired'); 00154 $noWait = ($i === 0); 00155 $isAcquired = TRUE; 00156 break; 00157 } 00158 usleep($this->step * 1000); 00159 } 00160 00161 if (!$isAcquired) { 00162 throw new Exception('Lock file could not be created'); 00163 } 00164 00165 t3lib_div::fixPermissions($this->resource); 00166 break; 00167 case 'flock': 00168 if (($this->filepointer = fopen($this->resource, 'w+')) == FALSE) { 00169 throw new Exception('Lock file could not be opened'); 00170 } 00171 00172 if (flock($this->filepointer, LOCK_EX | LOCK_NB) == TRUE) { // Lock without blocking 00173 $noWait = TRUE; 00174 } elseif (flock($this->filepointer, LOCK_EX) == TRUE) { // Lock with blocking (waiting for similar locks to become released) 00175 $noWait = FALSE; 00176 } else { 00177 throw new Exception('Could not lock file "' . $this->resource . '"'); 00178 } 00179 break; 00180 case 'semaphore': 00181 if (sem_acquire($this->resource)) { 00182 // 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. 00183 $noWait = FALSE; 00184 } 00185 break; 00186 case 'disable': 00187 $noWait = FALSE; 00188 $isAcquired = FALSE; 00189 break; 00190 } 00191 00192 $this->isAcquired = $isAcquired; 00193 return $noWait; 00194 } 00195 00196 /** 00197 * Release the lock 00198 * 00199 * @return boolean Returns TRUE on success or FALSE on failure 00200 */ 00201 public function release() { 00202 if (!$this->isAcquired) { 00203 return TRUE; 00204 } 00205 00206 $success = TRUE; 00207 switch ($this->method) { 00208 case 'simple': 00209 if (unlink($this->resource) == FALSE) { 00210 $success = FALSE; 00211 } 00212 break; 00213 case 'flock': 00214 if (flock($this->filepointer, LOCK_UN) == FALSE) { 00215 $success = FALSE; 00216 } 00217 fclose($this->filepointer); 00218 unlink($this->resource); 00219 break; 00220 case 'semaphore': 00221 if (@sem_release($this->resource)) { 00222 sem_remove($this->resource); 00223 } else { 00224 $success = FALSE; 00225 } 00226 break; 00227 case 'disable': 00228 $success = FALSE; 00229 break; 00230 } 00231 00232 $this->isAcquired = FALSE; 00233 return $success; 00234 } 00235 00236 /** 00237 * Return the locking method which is currently used 00238 * 00239 * @return string Locking method 00240 */ 00241 public function getMethod() { 00242 return $this->method; 00243 } 00244 00245 /** 00246 * Return the ID which is currently used 00247 * 00248 * @return string Locking ID 00249 */ 00250 public function getId() { 00251 return $this->id; 00252 } 00253 00254 /** 00255 * Return the resource which is currently used. 00256 * Depending on the locking method this can be a filename or a semaphore resource. 00257 * 00258 * @return mixed Locking resource (filename as string or semaphore as resource) 00259 */ 00260 public function getResource() { 00261 return $this->resource; 00262 } 00263 00264 /** 00265 * Return the status of a lock 00266 * 00267 * @return string Returns TRUE if lock is acquired, FALSE otherwise 00268 */ 00269 public function getLockStatus() { 00270 return $this->isAcquired; 00271 } 00272 00273 /** 00274 * Sets the facility (extension name) for the syslog entry. 00275 * 00276 * @param string $syslogFacility 00277 */ 00278 public function setSyslogFacility($syslogFacility) { 00279 $this->syslogFacility = $syslogFacility; 00280 } 00281 00282 /** 00283 * Enable/ disable logging 00284 * 00285 * @param boolean $isLoggingEnabled 00286 */ 00287 public function setEnableLogging($isLoggingEnabled) { 00288 $this->isLoggingEnabled = $isLoggingEnabled; 00289 } 00290 00291 /** 00292 * Adds a common log entry for this locking API using t3lib_div::sysLog(). 00293 * Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired 00294 * 00295 * @param string $message: The message to be logged 00296 * @param integer $severity: Severity - 0 is info (default), 1 is notice, 2 is warning, 3 is error, 4 is fatal error 00297 * @return void 00298 */ 00299 public function sysLog($message, $severity = 0) { 00300 if ($this->isLoggingEnabled) { 00301 t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), $this->syslogFacility, $severity); 00302 } 00303 } 00304 } 00305 00306 00307 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock.php'])) { 00308 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock.php']); 00309 } 00310 ?>
1.8.0