|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZMutex class 00004 // 00005 // Created on: <24-Apr-2007 18:59:49 hovik> 00006 // 00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00008 // SOFTWARE NAME: eZ Publish 00009 // SOFTWARE RELEASE: 4.0.x 00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS 00011 // SOFTWARE LICENSE: GNU General Public License v2.0 00012 // NOTICE: > 00013 // This program is free software; you can redistribute it and/or 00014 // modify it under the terms of version 2.0 of the GNU General 00015 // Public License as published by the Free Software Foundation. 00016 // 00017 // This program is distributed in the hope that it will be useful, 00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 // GNU General Public License for more details. 00021 // 00022 // You should have received a copy of version 2.0 of the GNU General 00023 // Public License along with this program; if not, write to the Free 00024 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00025 // MA 02110-1301, USA. 00026 // 00027 // 00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ## 00029 // 00030 00031 /*! \file ezmutex.php 00032 */ 00033 00034 /*! 00035 \class eZMutex ezmutex.php 00036 \brief The class eZMutex provides a file based mutex. The mutex works across processes. 00037 00038 */ 00039 00040 //include_once( 'lib/ezutils/classes/ezsys.php' ); 00041 //include_once( 'lib/ezfile/classes/ezfile.php' ); 00042 00043 class eZMutex 00044 { 00045 const STEAL_STRING = '_eZMutex_Steal'; 00046 00047 /*! 00048 Constructor. Creates a mutex object for 00049 mutext <name>. The mutex is file based, and a 00050 mutex is valid across PHP processes. 00051 00052 \param mutex name 00053 */ 00054 function eZMutex( $name ) 00055 { 00056 //include_once( 'lib/ezutils/classes/ezdir.php' ); 00057 $this->Name = md5( $name ); 00058 $mutexPath = eZDir::path( array( eZSys::cacheDirectory(), 00059 'ezmutex' ) ); 00060 eZDir::mkdir( $mutexPath, false, true ); 00061 $this->FileName = eZDir::path( array( $mutexPath, 00062 $this->Name ) ); 00063 $this->MetaFileName = eZDir::path( array( $mutexPath, 00064 $this->Name . '_meta' ) ); 00065 } 00066 00067 /*! 00068 \private 00069 Get file pointer 00070 */ 00071 function fp() 00072 { 00073 if ( !isset( $GLOBALS['eZMutex_FP_' . $this->FileName] ) || 00074 $GLOBALS['eZMutex_FP_' . $this->FileName] === false ) 00075 { 00076 $GLOBALS['eZMutex_FP_' . $this->FileName] = fopen( $this->FileName, 'w' ); 00077 if ( $GLOBALS['eZMutex_FP_' . $this->FileName] === false ) 00078 { 00079 eZDebug::writeError( 'Failed to open file: ' . $this->FileName ); 00080 } 00081 } 00082 return $GLOBALS['eZMutex_FP_' . $this->FileName]; 00083 } 00084 00085 /*! 00086 Test if mutex is locked. 00087 00088 \return true if mutex is locked 00089 */ 00090 function test() 00091 { 00092 if ( $fp = $this->fp() ) 00093 { 00094 if ( flock( $fp, LOCK_EX | LOCK_NB ) ) 00095 { 00096 flock( $fp, LOCK_UN ); 00097 return false; 00098 } 00099 } 00100 return true; 00101 } 00102 00103 /*! 00104 Lock. Blocks untill the mutex becomes available 00105 00106 \return true if lock is successfull. 00107 false if it fails to require a lock. 00108 */ 00109 function lock() 00110 { 00111 if ( $fp = $this->fp() ) 00112 { 00113 if ( flock( $fp, LOCK_EX ) ) 00114 { 00115 $this->clearMeta(); 00116 $this->setMeta( 'timestamp', time() ); 00117 return true; 00118 } 00119 } 00120 return false; 00121 } 00122 00123 /*! 00124 Set metadata 00125 00126 \param key 00127 \param value 00128 */ 00129 function setMeta( $key, $value ) 00130 { 00131 $tmpFile = $this->MetaFileName . substr( md5( mt_rand() ), 0, 8 ); 00132 $content = array(); 00133 if ( file_exists( $this->MetaFileName ) ) 00134 { 00135 $content = unserialize( eZFile::getContents( $this->MetaFileName ) ); 00136 } 00137 $content[$key] = $value; 00138 eZFile::create( $tmpFile, false, serialize( $content) ); 00139 eZFile::rename( $tmpFile, $this->MetaFileName ); 00140 } 00141 00142 /*! 00143 Read meta data 00144 00145 \param key 00146 00147 \return value, null if no value is associated with the key. 00148 */ 00149 function meta( $key ) 00150 { 00151 $content = array(); 00152 if ( file_exists( $this->MetaFileName ) ) 00153 { 00154 $content = unserialize( eZFile::getContents( $this->MetaFileName ) ); 00155 } 00156 return isset( $content[$key] ) ? $content[$key] : null; 00157 } 00158 00159 /*! 00160 Clear the meta data 00161 */ 00162 function clearMeta() 00163 { 00164 $tmpFile = $this->MetaFileName . substr( md5( mt_rand() ), 0, 8 ); 00165 $content = array(); 00166 eZFile::create( $tmpFile, false, serialize( $content) ); 00167 eZFile::rename( $tmpFile, $this->MetaFileName ); 00168 } 00169 00170 /*! 00171 Unlock. Unlocks the mutex. 00172 00173 \return true if the unlock is successfull. 00174 */ 00175 function unlock() 00176 { 00177 if ( $fp = $this->fp() ) 00178 { 00179 fclose( $fp ); 00180 @unlink( $this->MetaFileName ); 00181 @unlink( $this->FileName ); 00182 $GLOBALS['eZMutex_FP_' . $this->FileName] = false; 00183 } 00184 return false; 00185 } 00186 00187 /*! 00188 Get the timestamp of when the mutex was locked 00189 00190 \return GMT timestamp of when the mutex was created. 00191 false if no lock exists. 00192 */ 00193 function lockTS() 00194 { 00195 return $this->test() ? $this->meta( 'timestamp' ) : false; 00196 } 00197 00198 /*! 00199 Steal. The function will aquire a lock on the mutex when it's stolen. 00200 <code> 00201 $myMutex = new eZMutex( 'myMutex' ); 00202 if ( $myMutex->steal() ) 00203 { 00204 // protected code goes here 00205 $myMutex->unlock(); 00206 } 00207 </code> 00208 00209 \param force. If this is set to true, the process will steal the mutex, even if other processes are in the 00210 process of stealing it as well. 00211 00212 \return false If the process is not able to steal the mutex. 00213 true if the mutex is successfully stolen. 00214 */ 00215 function steal( $force = false ) 00216 { 00217 $stealMutex = new eZMutex( $this->Name . eZMutex::STEAL_STRING ); 00218 if ( !$force ) 00219 { 00220 // Aquire a steal mutex, and steal the mutex. 00221 if ( $stealMutex->test() ) 00222 { 00223 return false; 00224 } 00225 if ( $stealMutex->lock() ) 00226 { 00227 $stealMutex->setMeta( 'pid', getmypid() ); 00228 if ( $this->lock() ) 00229 { 00230 // sleep for 1 second in case lock has only been granted beacause a larger 00231 // cleanup is in progress. 00232 sleep( 1 ); 00233 $stealMutex->unlock(); 00234 return true; 00235 } 00236 } 00237 } 00238 else 00239 { 00240 $stealPid = $stealMutex->meta( 'pid' ); 00241 if ( is_numeric( $stealPid ) && 00242 $stealPid != 0 && 00243 function_exists( 'posix_kill' ) ) 00244 { 00245 eZDebug::writeNotice( 'Killing steal mutex process: ' . $stealPid ); 00246 posix_kill( $stealPid, 9 ); 00247 } 00248 00249 // If other steal mutex exists, kill it, and create your own. 00250 $this->unlock(); 00251 return $this->lock(); 00252 } 00253 return false; 00254 } 00255 00256 public $Name; 00257 public $FileName; 00258 } 00259 00260 ?>