|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZMutex class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package lib 00009 */ 00010 00011 /*! 00012 \class eZMutex ezmutex.php 00013 \brief The class eZMutex provides a file based mutex. The mutex works across processes. 00014 00015 */ 00016 00017 class eZMutex 00018 { 00019 const STEAL_STRING = '_eZMutex_Steal'; 00020 00021 /*! 00022 Constructor. Creates a mutex object for 00023 mutext <name>. The mutex is file based, and a 00024 mutex is valid across PHP processes. 00025 00026 \param mutex name 00027 */ 00028 function eZMutex( $name ) 00029 { 00030 $this->Name = md5( $name ); 00031 $mutexPath = eZDir::path( array( eZSys::cacheDirectory(), 00032 'ezmutex' ) ); 00033 eZDir::mkdir( $mutexPath, false, true ); 00034 $this->FileName = eZDir::path( array( $mutexPath, 00035 $this->Name ) ); 00036 $this->MetaFileName = eZDir::path( array( $mutexPath, 00037 $this->Name . '_meta' ) ); 00038 } 00039 00040 /*! 00041 \private 00042 Get file pointer 00043 */ 00044 function fp() 00045 { 00046 if ( !isset( $GLOBALS['eZMutex_FP_' . $this->FileName] ) || 00047 $GLOBALS['eZMutex_FP_' . $this->FileName] === false ) 00048 { 00049 $GLOBALS['eZMutex_FP_' . $this->FileName] = fopen( $this->FileName, 'w' ); 00050 if ( $GLOBALS['eZMutex_FP_' . $this->FileName] === false ) 00051 { 00052 eZDebug::writeError( 'Failed to open file: ' . $this->FileName ); 00053 } 00054 } 00055 return $GLOBALS['eZMutex_FP_' . $this->FileName]; 00056 } 00057 00058 /*! 00059 Test if mutex is locked. 00060 00061 \return true if mutex is locked 00062 */ 00063 function test() 00064 { 00065 if ( $fp = $this->fp() ) 00066 { 00067 if ( flock( $fp, LOCK_EX | LOCK_NB ) ) 00068 { 00069 flock( $fp, LOCK_UN ); 00070 return false; 00071 } 00072 } 00073 return true; 00074 } 00075 00076 /*! 00077 Lock. Blocks untill the mutex becomes available 00078 00079 \return true if lock is successfull. 00080 false if it fails to require a lock. 00081 */ 00082 function lock() 00083 { 00084 if ( $fp = $this->fp() ) 00085 { 00086 if ( flock( $fp, LOCK_EX ) ) 00087 { 00088 $this->clearMeta(); 00089 $this->setMeta( 'timestamp', time() ); 00090 return true; 00091 } 00092 } 00093 return false; 00094 } 00095 00096 /*! 00097 Set metadata 00098 00099 \param key 00100 \param value 00101 */ 00102 function setMeta( $key, $value ) 00103 { 00104 $content = array(); 00105 if ( file_exists( $this->MetaFileName ) ) 00106 { 00107 $content = unserialize( file_get_contents( $this->MetaFileName ) ); 00108 } 00109 $content[$key] = $value; 00110 eZFile::create( $this->MetaFileName, false, serialize( $content), true ); 00111 } 00112 00113 /*! 00114 Read meta data 00115 00116 \param key 00117 00118 \return value, null if no value is associated with the key. 00119 */ 00120 function meta( $key ) 00121 { 00122 $content = array(); 00123 if ( file_exists( $this->MetaFileName ) ) 00124 { 00125 $content = unserialize( file_get_contents( $this->MetaFileName ) ); 00126 } 00127 return isset( $content[$key] ) ? $content[$key] : null; 00128 } 00129 00130 /*! 00131 Clear the meta data 00132 */ 00133 function clearMeta() 00134 { 00135 $content = array(); 00136 eZFile::create( $this->MetaFileName, false, serialize( $content), true ); 00137 } 00138 00139 /*! 00140 Unlock. Unlocks the mutex. 00141 00142 \return true if the unlock is successfull. 00143 */ 00144 function unlock() 00145 { 00146 if ( $fp = $this->fp() ) 00147 { 00148 fclose( $fp ); 00149 @unlink( $this->MetaFileName ); 00150 @unlink( $this->FileName ); 00151 $GLOBALS['eZMutex_FP_' . $this->FileName] = false; 00152 } 00153 return false; 00154 } 00155 00156 /*! 00157 Get the timestamp of when the mutex was locked 00158 00159 \return GMT timestamp of when the mutex was created. 00160 false if no lock exists. 00161 */ 00162 function lockTS() 00163 { 00164 return $this->test() ? $this->meta( 'timestamp' ) : false; 00165 } 00166 00167 /*! 00168 Steal. The function will aquire a lock on the mutex when it's stolen. 00169 <code> 00170 $myMutex = new eZMutex( 'myMutex' ); 00171 if ( $myMutex->steal() ) 00172 { 00173 // protected code goes here 00174 $myMutex->unlock(); 00175 } 00176 </code> 00177 00178 \param force. If this is set to true, the process will steal the mutex, even if other processes are in the 00179 process of stealing it as well. 00180 00181 \return false If the process is not able to steal the mutex. 00182 true if the mutex is successfully stolen. 00183 */ 00184 function steal( $force = false ) 00185 { 00186 $stealMutex = new eZMutex( $this->Name . eZMutex::STEAL_STRING ); 00187 if ( !$force ) 00188 { 00189 // Aquire a steal mutex, and steal the mutex. 00190 if ( $stealMutex->test() ) 00191 { 00192 return false; 00193 } 00194 if ( $stealMutex->lock() ) 00195 { 00196 $stealMutex->setMeta( 'pid', getmypid() ); 00197 if ( $this->lock() ) 00198 { 00199 // sleep for 1 second in case lock has only been granted beacause a larger 00200 // cleanup is in progress. 00201 sleep( 1 ); 00202 $stealMutex->unlock(); 00203 return true; 00204 } 00205 } 00206 } 00207 else 00208 { 00209 $stealPid = $stealMutex->meta( 'pid' ); 00210 if ( is_numeric( $stealPid ) && 00211 $stealPid != 0 && 00212 function_exists( 'posix_kill' ) ) 00213 { 00214 eZDebug::writeNotice( 'Killing steal mutex process: ' . $stealPid ); 00215 posix_kill( $stealPid, 9 ); 00216 } 00217 00218 // If other steal mutex exists, kill it, and create your own. 00219 $this->unlock(); 00220 return $this->lock(); 00221 } 00222 return false; 00223 } 00224 00225 public $Name; 00226 public $FileName; 00227 } 00228 00229 ?>