Sindbad~EG File Manager

Current Path : /var/www/web3/modules/core/classes/
Upload File :
Current File : //var/www/web3/modules/core/classes/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()));
    }
}
?>

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists