File indexing completed on 2025-01-19 05:21:27
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Search_Lucene 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** Zend_Search_Lucene_Storage_Directory */ 0023 // require_once 'Zend/Search/Lucene/Storage/Directory.php'; 0024 0025 /** Zend_Search_Lucene_Storage_File */ 0026 // require_once 'Zend/Search/Lucene/Storage/File.php'; 0027 0028 /** 0029 * This is an utility class which provides index locks processing functionality 0030 * 0031 * @category Zend 0032 * @package Zend_Search_Lucene 0033 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0034 * @license http://framework.zend.com/license/new-bsd New BSD License 0035 */ 0036 class Zend_Search_Lucene_LockManager 0037 { 0038 /** 0039 * consts for name of file to show lock status 0040 */ 0041 const WRITE_LOCK_FILE = 'write.lock.file'; 0042 const READ_LOCK_FILE = 'read.lock.file'; 0043 const READ_LOCK_PROCESSING_LOCK_FILE = 'read-lock-processing.lock.file'; 0044 const OPTIMIZATION_LOCK_FILE = 'optimization.lock.file'; 0045 0046 /** 0047 * Obtain exclusive write lock on the index 0048 * 0049 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0050 * @return Zend_Search_Lucene_Storage_File 0051 * @throws Zend_Search_Lucene_Exception 0052 */ 0053 public static function obtainWriteLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0054 { 0055 $lock = $lockDirectory->createFile(self::WRITE_LOCK_FILE); 0056 if (!$lock->lock(LOCK_EX)) { 0057 // require_once 'Zend/Search/Lucene/Exception.php'; 0058 throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive index lock'); 0059 } 0060 return $lock; 0061 } 0062 0063 /** 0064 * Release exclusive write lock 0065 * 0066 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0067 */ 0068 public static function releaseWriteLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0069 { 0070 $lock = $lockDirectory->getFileObject(self::WRITE_LOCK_FILE); 0071 $lock->unlock(); 0072 } 0073 0074 /** 0075 * Obtain the exclusive "read escalation/de-escalation" lock 0076 * 0077 * Required to protect the escalate/de-escalate read lock process 0078 * on GFS (and potentially other) mounted filesystems. 0079 * 0080 * Why we need this: 0081 * While GFS supports cluster-wide locking via flock(), it's 0082 * implementation isn't quite what it should be. The locking 0083 * semantics that work consistently on a local filesystem tend to 0084 * fail on GFS mounted filesystems. This appears to be a design defect 0085 * in the implementation of GFS. How this manifests itself is that 0086 * conditional promotion of a shared lock to exclusive will always 0087 * fail, lock release requests are honored but not immediately 0088 * processed (causing erratic failures of subsequent conditional 0089 * requests) and the releasing of the exclusive lock before the 0090 * shared lock is set when a lock is demoted (which can open a window 0091 * of opportunity for another process to gain an exclusive lock when 0092 * it shoudln't be allowed to). 0093 * 0094 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0095 * @return Zend_Search_Lucene_Storage_File 0096 * @throws Zend_Search_Lucene_Exception 0097 */ 0098 private static function _startReadLockProcessing(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0099 { 0100 $lock = $lockDirectory->createFile(self::READ_LOCK_PROCESSING_LOCK_FILE); 0101 if (!$lock->lock(LOCK_EX)) { 0102 // require_once 'Zend/Search/Lucene/Exception.php'; 0103 throw new Zend_Search_Lucene_Exception('Can\'t obtain exclusive lock for the read lock processing file'); 0104 } 0105 return $lock; 0106 } 0107 0108 /** 0109 * Release the exclusive "read escalation/de-escalation" lock 0110 * 0111 * Required to protect the escalate/de-escalate read lock process 0112 * on GFS (and potentially other) mounted filesystems. 0113 * 0114 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0115 */ 0116 private static function _stopReadLockProcessing(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0117 { 0118 $lock = $lockDirectory->getFileObject(self::READ_LOCK_PROCESSING_LOCK_FILE); 0119 $lock->unlock(); 0120 } 0121 0122 0123 /** 0124 * Obtain shared read lock on the index 0125 * 0126 * It doesn't block other read or update processes, but prevent index from the premature cleaning-up 0127 * 0128 * @param Zend_Search_Lucene_Storage_Directory $defaultLockDirectory 0129 * @return Zend_Search_Lucene_Storage_File 0130 * @throws Zend_Search_Lucene_Exception 0131 */ 0132 public static function obtainReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0133 { 0134 $lock = $lockDirectory->createFile(self::READ_LOCK_FILE); 0135 if (!$lock->lock(LOCK_SH)) { 0136 // require_once 'Zend/Search/Lucene/Exception.php'; 0137 throw new Zend_Search_Lucene_Exception('Can\'t obtain shared reading index lock'); 0138 } 0139 return $lock; 0140 } 0141 0142 /** 0143 * Release shared read lock 0144 * 0145 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0146 */ 0147 public static function releaseReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0148 { 0149 $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); 0150 $lock->unlock(); 0151 } 0152 0153 /** 0154 * Escalate Read lock to exclusive level 0155 * 0156 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0157 * @return boolean 0158 */ 0159 public static function escalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0160 { 0161 self::_startReadLockProcessing($lockDirectory); 0162 0163 $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); 0164 0165 // First, release the shared lock for the benefit of GFS since 0166 // it will fail the conditional request to promote the lock to 0167 // "exclusive" while the shared lock is held (even when we are 0168 // the only holder). 0169 $lock->unlock(); 0170 0171 // GFS is really poor. While the above "unlock" returns, GFS 0172 // doesn't clean up it's tables right away (which will potentially 0173 // cause the conditional locking for the "exclusive" lock to fail. 0174 // We will retry the conditional lock request several times on a 0175 // failure to get past this. The performance hit is negligible 0176 // in the grand scheme of things and only will occur with GFS 0177 // filesystems or if another local process has the shared lock 0178 // on local filesystems. 0179 for ($retries = 0; $retries < 10; $retries++) { 0180 if ($lock->lock(LOCK_EX, true)) { 0181 // Exclusive lock is obtained! 0182 self::_stopReadLockProcessing($lockDirectory); 0183 return true; 0184 } 0185 0186 // wait 1 microsecond 0187 usleep(1); 0188 } 0189 0190 // Restore lock state 0191 $lock->lock(LOCK_SH); 0192 0193 self::_stopReadLockProcessing($lockDirectory); 0194 return false; 0195 } 0196 0197 /** 0198 * De-escalate Read lock to shared level 0199 * 0200 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0201 */ 0202 public static function deEscalateReadLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0203 { 0204 $lock = $lockDirectory->getFileObject(self::READ_LOCK_FILE); 0205 $lock->lock(LOCK_SH); 0206 } 0207 0208 /** 0209 * Obtain exclusive optimization lock on the index 0210 * 0211 * Returns lock object on success and false otherwise (doesn't block execution) 0212 * 0213 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0214 * @return mixed 0215 */ 0216 public static function obtainOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0217 { 0218 $lock = $lockDirectory->createFile(self::OPTIMIZATION_LOCK_FILE); 0219 if (!$lock->lock(LOCK_EX, true)) { 0220 return false; 0221 } 0222 return $lock; 0223 } 0224 0225 /** 0226 * Release exclusive optimization lock 0227 * 0228 * @param Zend_Search_Lucene_Storage_Directory $lockDirectory 0229 */ 0230 public static function releaseOptimizationLock(Zend_Search_Lucene_Storage_Directory $lockDirectory) 0231 { 0232 $lock = $lockDirectory->getFileObject(self::OPTIMIZATION_LOCK_FILE); 0233 $lock->unlock(); 0234 } 0235 0236 }