0byt3m1n1
Path:
/
data
/
applications
/
aps
/
gallery
/
2.2-08
/
htdocs
/
modules
/
core
/
classes
/
[
Home
]
File: FlockLockSystem.class
<?php /* * Gallery - a web based photo album viewer and editor * Copyright (C) 2000-2007 Bharat Mediratta * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ GalleryCoreApi::requireOnce('modules/core/classes/GalleryLockSystem.class'); /** * Flock() based locking. This is fairly efficient, but it will not work on NFS and is known to be * unreliable on some operating systems including some flavors of the 2.4 Linux kernel. * @package GalleryCore * @subpackage Classes * @author Bharat Mediratta <bharat@menalto.com> * @author Alan Harder <alan.harder@sun.com> * @version $Revision: 15799 $ */ class FlockLockSystem extends GalleryLockSystem { /** * Reference counts for every lock we're holding so that if we've got a file doubly read locked * we don't try to delete it until all read locks are released. * @todo When we get rid of double read locks, we can delete this. * @var array * @access private */ var $_references; /** * @see GalleryLockSystem::_acquireLock */ function _acquireLock($ids, $timeout, $lockType) { global $gallery; $platform =& $gallery->getPlatform(); $cutoffTime = time() + $timeout; /* Get a file handle (which is actually a lock handle) for all the files first */ $notLocked = array(); foreach ($ids as $id) { $lockFile = $this->_getLockFile($id); $fd = $platform->fopen($lockFile, 'wb+'); if ($fd) { $notLocked[$id] = array($fd, $lockFile); } else { /* Close the files that we already opened successfully and return an error */ foreach ($notLocked as $lockInfo) { list ($fd, $lockFile) = $lockInfo; $platform->fclose($fd); /* * Delete the lock files even if others are locking it too (releaseLock calls * are too often forgotten in error handling) */ if ($platform->file_exists($lockFile)) { @$platform->unlink($lockFile); } } return array(GalleryCoreApi::error(ERROR_PLATFORM_FAILURE, __FILE__, __LINE__, $lockFile), null); } } /* Move them from notLocked -> locked as we acquire the lock */ $locked = array(); $wouldBlock = null; $flockType = ($lockType == LOCK_READ) ? LOCK_SH : LOCK_EX; while (!empty($notLocked)) { $tmp = $notLocked; $notLocked = array(); foreach ($tmp as $id => $lockInfo) { list ($fd, $lockFile) = $lockInfo; /* Check if we can lock */ $flockReturned = $platform->flock($fd, $flockType | LOCK_NB, $wouldBlock); if ($flockReturned && !$wouldBlock) { $locked[$id] = $lockInfo; /* Keep track of the number of locks there are for this object */ if (isset($this->_references[$lockFile])) { $this->_references[$lockFile]++; } else { $this->_references[$lockFile] = 1; } } else { /* Remember that it's not locked and keep going */ $notLocked[$id] = $lockInfo; } } if (!empty($notLocked)) { if (time() > $cutoffTime) { /* Couldn't get the locks in time, release the ones that we have and return */ foreach (array_merge($locked, $notLocked) as $lockInfo) { $this->_closeLockFile($lockInfo); } return array(GalleryCoreApi::error(ERROR_LOCK_TIMEOUT, __FILE__, __LINE__, array_reduce($notLocked, create_function('$v,$w', 'return empty($v) ? $w[1] : "$v $w[1]";'))), null); } /* Wait a second and try any unacquired locks again */ $gallery->debug('Waiting for a lock'); sleep(1); } } $lockId = crc32(microtime()); $this->_locks[$lockId] = array('lockId' => $lockId, 'type' => $lockType, 'ids' => $locked); return array(null, $lockId); } /** * @see GalleryLockSystem::_releaseLocksNow */ function _releaseLocksNow($locks) { global $gallery; $gallery->guaranteeTimeLimit(count($locks) + 5); /* Release all locks by closing the files */ foreach ($locks as $lock) { foreach ($lock['ids'] as $lockInfo) { $this->_closeLockFile($lockInfo); } } return null; } /** * @see GalleryLockSystem::refreshLocks */ function refreshLocks($freshUntil) { global $gallery; $platform =& $gallery->getPlatform(); /* Flush one byte to each lock file to update its timestamp */ foreach ($this->_locks as $lockId => $lock) { foreach ($lock['ids'] as $lockInfo) { list ($fd, $lockFile) = $lockInfo; $count = $platform->fwrite($fd, '.'); if ($count == 0) { return GalleryCoreApi::error(ERROR_STORAGE_FAILURE, __FILE__, __LINE__, $lockFile); } $platform->fflush($fd); } } return null; } /** * Return the lock file for a given object id. * @param int $id the input id * @return string the complete path to the lock file * @access private */ function _getLockFile($id) { global $gallery; return $gallery->getConfig('data.gallery.locks') . (int)$id; } /** * Close file for this lock and remove file if there are no more references. * @param array $lockInfo lockInfo * @access private */ function _closeLockFile($lockInfo) { global $gallery; $platform =& $gallery->getPlatform(); list ($fd, $lockFile) = $lockInfo; $platform->fclose($fd); if ($platform->file_exists($lockFile)) { $this->_references[$lockFile]--; if ($this->_references[$lockFile] == 0) { $platform->unlink($lockFile); } } } /** * @see GalleryLockSystem::_removeObjectsFromLock */ function _removeObjectsFromLock(&$lock, $ids) { foreach ($ids as $id) { $this->_closeLockFile($lock['ids'][$id]); unset($lock['ids'][$id]); } return null; } /** * @see GalleryLockSystem::_newLockId */ function _newLockId() { return array(null, crc32(microtime())); } } ?>