From dc1e3620d239ad4fbfb3a80610949abb0c9a4ecd Mon Sep 17 00:00:00 2001 From: ringmaster Date: Fri, 23 May 2014 10:29:37 -0400 Subject: [PATCH] Continued flock work. --- apps/files_external/lib/streamwrapper.php | 1 + .../files/storage/wrapper/lockingwrapper.php | 34 +++++------- lib/public/files/lock.php | 52 +++++++++++++++++-- lib/public/files/storage.php | 1 - 4 files changed, 64 insertions(+), 24 deletions(-) diff --git a/apps/files_external/lib/streamwrapper.php b/apps/files_external/lib/streamwrapper.php index d749f62afe7..44bd9a0161a 100644 --- a/apps/files_external/lib/streamwrapper.php +++ b/apps/files_external/lib/streamwrapper.php @@ -103,4 +103,5 @@ abstract class StreamWrapper extends Common { public function stat($path) { return stat($this->constructUrl($path)); } + } diff --git a/lib/private/files/storage/wrapper/lockingwrapper.php b/lib/private/files/storage/wrapper/lockingwrapper.php index 04a325940bf..42a018fdc66 100644 --- a/lib/private/files/storage/wrapper/lockingwrapper.php +++ b/lib/private/files/storage/wrapper/lockingwrapper.php @@ -34,7 +34,7 @@ class LockingWrapper extends Wrapper { * @return bool|\OCP\Files\Lock Lock instance on success, false on failure */ protected function getLock($path, $lockType){ - $path = Filesystem::normalizePath($path); + $path = Filesystem::normalizePath($this->storage->getLocalFile($path)); if(!isset($this->locks[$path])) { $this->locks[$path] = new Lock($path); } @@ -48,7 +48,7 @@ class LockingWrapper extends Wrapper { * @return bool true on success, false on failure */ protected function releaseLock($path, $lockType, $releaseAll = false){ - $path = Filesystem::normalizePath($path); + $path = Filesystem::normalizePath($this->storage->getLocalFile($path)); if(isset($this->locks[$path])) { if($releaseAll) { return $this->locks[$path]->releaseAll(); @@ -68,9 +68,7 @@ class LockingWrapper extends Wrapper { */ public function file_get_contents($path) { try { - if (!$this->getLock($path, Lock::READ)) { - throw new LockNotAcquiredException($path, Lock::READ); - } + $this->getLock($path, Lock::READ); $result = $this->storage->file_get_contents($path); } catch(\Exception $originalException) { @@ -78,14 +76,13 @@ class LockingWrapper extends Wrapper { $this->releaseLock($path, Lock::READ); throw $originalException; } + $this->releaseLock($path, Lock::READ); return $result; } public function file_put_contents($path, $data) { try { - if (!$this->getLock($path, Lock::WRITE)) { - throw new LockNotAcquiredException($path, Lock::WRITE); - } + $this->getLock($path, Lock::WRITE); $result = $this->storage->file_put_contents($path, $data); } catch(\Exception $originalException) { @@ -93,18 +90,15 @@ class LockingWrapper extends Wrapper { $this->releaseLock($path, Lock::WRITE); throw $originalException; } + $this->releaseLock($path, Lock::WRITE); return $result; } public function copy($path1, $path2) { try { - if (!$this->getLock($path1, Lock::READ)) { - throw new LockNotAcquiredException($path1, Lock::READ); - } - if (!$this->getLock($path2, Lock::WRITE)) { - throw new LockNotAcquiredException($path2, Lock::WRITE); - } + $this->getLock($path1, Lock::READ); + $this->getLock($path2, Lock::WRITE); $result = $this->storage->copy($path1, $path2); } catch(\Exception $originalException) { @@ -113,17 +107,15 @@ class LockingWrapper extends Wrapper { $this->releaseLock($path2, Lock::WRITE); throw $originalException; } + $this->releaseLock($path1, Lock::READ); + $this->releaseLock($path2, Lock::WRITE); return $result; } public function rename($path1, $path2) { try { - if (!$this->getLock($path1, Lock::READ)) { - throw new LockNotAcquiredException($path1, Lock::READ); - } - if (!$this->getLock($path2, Lock::WRITE)) { - throw new LockNotAcquiredException($path2, Lock::WRITE); - } + $this->getLock($path1, Lock::READ); + $this->getLock($path2, Lock::WRITE); $result = $this->storage->rename($path1, $path2); } catch(\Exception $originalException) { @@ -132,6 +124,8 @@ class LockingWrapper extends Wrapper { $this->releaseLock($path2, Lock::WRITE); throw $originalException; } + $this->releaseLock($path1, Lock::READ); + $this->releaseLock($path2, Lock::WRITE); return $result; } diff --git a/lib/public/files/lock.php b/lib/public/files/lock.php index fb1e4b9f1c5..cc39e674b50 100644 --- a/lib/public/files/lock.php +++ b/lib/public/files/lock.php @@ -17,6 +17,7 @@ */ namespace OCP\Files; +use OC\Files\Filesystem; /** * Class Lock @@ -29,13 +30,50 @@ class Lock { /** @var string $path Filename of the file as represented in storage */ protected $path; + /** @var array $stack A stack of lock data */ + protected $stack = array(); + + /** @var int $retries Number of lock retries to attempt */ + public static $retries = 40; + + /** @var int $retryInterval Milliseconds between retries */ + public static $retryInterval = 50; + + /** + * Constructor for the lock instance + * @param string $path Absolute pathname for a local file on which to obtain a lock + */ public function __construct($path) { - $this->path = $path; + $this->path = Filesystem::normalizePath($path); } + /** + * @param integer $lockType A constant representing the type of lock to queue + */ public function addLock($lockType) { - // This class is a stub/base for classes that implement locks - // We don't actually care what kind of lock we're queuing here + \OC_Log::write('lock', sprintf('INFO: Lock type %d requested for %s', $lockType, $this->path), \OC_Log::DEBUG); + $timeout = self::$retries; + + if(!isset($this->stack[$lockType])) { + // does lockfile exist? + // yes + // Acquire exclusive lock on lockfile? + // yes + // Delete lockfile, release lock + // no + // Sleep for configurable milliseconds - start over + // no + // Acquire shared lock on original file? + // yes + // Capture handle, return for action + // no + // Sleep for configurable milliseconds - start over + $handle = 1; + + $this->stack[$lockType] = array('handle' => $handle, 'count' => 0); + } + $this->stack[$lockType]['count']++; + } /** @@ -45,4 +83,12 @@ class Lock { return true; } + /** + * Release all queued locks on the file + * @return bool + */ + public function releaseAll() { + return true; + } + } \ No newline at end of file diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index 758cbb27377..323d20db564 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -35,7 +35,6 @@ namespace OCP\Files; * All paths passed to the storage are relative to the storage and should NOT have a leading slash. */ interface Storage { - /** * $parameters is a free form array with the configuration options needed to construct the storage * -- 2.39.5