Sindbad~EG File Manager

Current Path : /var/www/web3/modules/core/classes/
Upload File :
Current File : /var/www/web3/modules/core/classes/GalleryLockSystem.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.
 */

/**
 * 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