Sindbad~EG File Manager
<?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.
*/
/**
* This is an interface for all locking systems. You must extend it and
* implement all of its methods in order to introduce a new locking system.
*
* @package GalleryCore
* @subpackage Classes
* @author Bharat Mediratta <bharat@menalto.com>
* @author Alan Harder <alan.harder@sun.com>
* @version $Revision: 15513 $
* @abstract
*/
class GalleryLockSystem {
/**
* Information about all the locks we currently hold.
* array of (lockId => array('lockId' => lock id, 'type' => LOCK_READ or LOCK_WRITE,
* 'ids' => array of locked object id => additional data))
* @var array
* @access protected
*/
var $_locks;
/**
* List of locks that are pending release.
* array of (lockId => array('lockId' => lock id, 'type' => LOCK_READ or LOCK_WRITE,
* 'ids' => array of locked object id => additional data))
* @var array
* @access protected
*/
var $_releaseQueue;
function GalleryLockSystem() {
$this->_locks = $this->_releaseQueue = array();
}
/**
* Read lock one or more objects
*
* @param mixed $ids array of ids to lock, or single int id
* @param int $timeout (optional) how many seconds to wait for the lock before giving up
* @return array object GalleryStatus a status code
* mixed the lock id
*/
function acquireReadLock($ids, $timeout=10) {
if (!is_array($ids)) {
$ids = array($ids);
}
/*
* Close out write locks pending release that cover any of these ids
* (this does leave a window where another request could grab a lock)
*/
foreach ($this->_releaseQueue as $lockId => $lock) {
if ($lock['type'] != LOCK_WRITE) {
continue;
}
$foundIds = array_intersect(array_keys($lock['ids']), $ids);
if (count($foundIds) == count($lock['ids'])) {
/* Release this entire lock */
$ret = $this->_releaseLocksNow(array($lockId => $lock));
if ($ret) {
return array($ret, null);
}
unset($this->_releaseQueue[$lockId]);
} else if (!empty($foundIds)) {
/* Remove ids from this lock */
$ret = $this->_removeObjectsFromLock($this->_releaseQueue[$lockId], $foundIds);
if ($ret) {
return array($ret, null);
}
}
}
list ($ret, $lockId) = $this->_acquireLock($ids, $timeout, LOCK_READ);
if ($ret) {
return array($ret, null);
}
return array(null, $lockId);
}
/**
* Write lock one or more objects
*
* @param mixed $ids array of ids to lock, or single int id
* @param int $timeout (optional) how many seconds to wait for the lock before giving up
* @return array object GalleryStatus a status code
* mixed the lock id
*/
function acquireWriteLock($ids, $timeout=10) {
if (!is_array($ids)) {
$ids = array($ids);
}
/*
* Check for locks pending release that cover any of these ids.
* Move write locks between lockIds to keep lock in place; close out read locks
* (so read->write does leave a window where another request could grab a lock)
*/
$relock = array();
foreach ($this->_releaseQueue as $lockId => $lock) {
$foundIds = array_intersect(array_keys($lock['ids']), $ids);
if (empty($foundIds)) {
continue;
}
if ($lock['type'] == LOCK_WRITE) {
$relock[$lockId] = $foundIds;
$ids = array_diff($ids, $foundIds);
} else if (count($foundIds) == count($lock['ids'])) {
/* Release this entire read lock */
$ret = $this->_releaseLocksNow(array($lockId => $lock));
if ($ret) {
return array($ret, null);
}
unset($this->_releaseQueue[$lockId]);
} else if (!empty($foundIds)) {
/* Remove ids from this read lock */
$ret = $this->_removeObjectsFromLock($this->_releaseQueue[$lockId], $foundIds);
if ($ret) {
return array($ret, null);
}
}
}
if (!empty($ids)) {
list ($ret, $lockId) = $this->_acquireLock($ids, $timeout, LOCK_WRITE);
if ($ret) {
return array($ret, null);
}
} else {
list ($ret, $lockId) = $this->_newLockId();
if ($ret) {
return array($ret, null);
}
$this->_locks[$lockId] = array('lockId' => $lockId, 'type' => LOCK_WRITE);
}
if (!empty($relock)) {
$ret = $this->_moveObjectsBetweenLocks($relock, $lockId);
if ($ret) {
return array($ret, null);
}
}
return array(null, $lockId);
}
/**
* Extending class must implement this function to actually acquire a lock.
*
* @param array $ids of object ids
* @param int $timeout how many seconds to wait for the lock before giving up
* @param int $lockType LOCK_READ or LOCK_WRITE
* @return array object GalleryStatus a status code
* int the lock id
* @access protected
* @abstract
*/
function _acquireLock($ids, $timeout, $lockType) {
return array(GalleryCoreApi::error(ERROR_UNIMPLEMENTED), null);
}
/**
* Return true if the given id is read locked or write locked
*
* @param int $id an object id
* @return boolean true if the object is read locked
*/
function isReadLocked($id) {
foreach ($this->_locks as $lockId => $lock) {
if (isset($lock['ids'][$id])) {
return true;
}
}
return false;
}
/**
* Return true if the given id is write locked
*
* @param int $id an object id
* @return boolean true if the object is write locked
*/
function isWriteLocked($id) {
foreach ($this->_locks as $lockId => $lock) {
if ($lock['type'] == LOCK_WRITE && isset($lock['ids'][$id])) {
return true;
}
}
return false;
}
/**
* Release the given lock(s)
* (queue the specified locks for later release on transactional databases or release them
* immediately if transactions are not supported)
*
* @param mixed $lockIds array of lock ids, or a single lock id
* @return object GalleryStatus a status code
*/
function releaseLocks($lockIds) {
global $gallery;
$storage =& $gallery->getStorage();
if (!is_array($lockIds)) {
$lockIds = array($lockIds);
}
/* Remove any empty or invalid elements */
foreach ($lockIds as $key => $lockId) {
if (empty($lockId) || !isset($this->_locks[$lockId])) {
unset($lockIds[$key]);
}
}
/* Queue locks for release */
foreach ($lockIds as $lockId) {
$this->_releaseQueue[$lockId] = $this->_locks[$lockId];
unset($this->_locks[$lockId]);
}
if (!$storage->isTransactional()) {
$ret = $this->releaseQueue();
if ($ret) {
return $ret;
}
}
return null;
}
/**
* Cleanup any locks queued for release
*
* @return object GalleryStatus a status code
*/
function releaseQueue() {
if (!empty($this->_releaseQueue)) {
$ret = $this->_releaseLocksNow($this->_releaseQueue);
if ($ret) {
return $ret;
}
$this->_releaseQueue = array();
}
return null;
}
/**
* Release the given locks now
*
* @param array $locks of lockId => lock
* @return object GalleryStatus a status code
* @access protected
* @abstract
*/
function _releaseLocksNow($locks) {
return GalleryCoreApi::error(ERROR_UNIMPLEMENTED);
}
/**
* Remove some object ids from the given lock.
*
* @param array $lock
* @param array $ids ids to remove
* @return object GalleryStatus a status code
* @access protected
* @abstract
*/
function _removeObjectsFromLock(&$lock, $ids) {
return GalleryCoreApi::error(ERROR_UNIMPLEMENTED);
}
/**
* Move ids from givens locks into a new lock.
* Remove any locks that now have no objects remaining.
*
* @param array $relock of (lockId => array of ids)
* @param int $newLockId move ids into this lock
* @return object GalleryStatus a status code
* @access protected
*/
function _moveObjectsBetweenLocks($relock, $newLockId) {
foreach ($relock as $lockId => $ids) {
foreach ($ids as $id) {
$this->_locks[$newLockId]['ids'][$id] =
$this->_releaseQueue[$lockId]['ids'][$id];
unset($this->_releaseQueue[$lockId]['ids'][$id]);
}
if (empty($this->_releaseQueue[$lockId]['ids'])) {
unset($this->_releaseQueue[$lockId]);
}
}
return null;
}
/**
* Generate an id for a new lock.
*
* @return array object GalleryStatus a status code
* mixed lockId
* @access protected
* @abstract
*/
function _newLockId() {
return GalleryCoreApi::error(ERROR_UNIMPLEMENTED);
}
/**
* Release any locks that we're holding
*
* @return object GalleryStatus a status code
*/
function releaseAllLocks() {
$ret = $this->releaseLocks(array_keys($this->_locks));
if ($ret) {
return $ret;
}
return null;
}
/**
* Refresh all the locks that we hold so that they aren't accidentally considered expired
*
* @param int $freshUntil the new "fresh until" timestamp
* @return object GalleryStatus a status code
* @abstract
*/
function refreshLocks($freshUntil) {
return GalleryCoreApi::error(ERROR_UNIMPLEMENTED);
}
/**
* Return the ids of all the locks we hold
*
* @return array lock ids
*/
function getLockIds() {
return array_keys($this->_locks);
}
}
?>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists