diff --git a/lockfile.php b/lockfile.php new file mode 100644 index 0000000..91d1154 --- /dev/null +++ b/lockfile.php @@ -0,0 +1,111 @@ + */ + +/** The lock management of files */ +class lockfile +{ + /** The Exclusive lock file */ + public $storagelock = "./data/lockfile.lock"; + /** The Read-Only lock file */ + private $storagelockRO = FALSE; + + /** This function lock the storage file until all is written. + If an other processus want to lock, it hang until the lock is released */ + public function lockRW () + { + if (!is_dir (dirname ($this->storagelock))) + @mkdir (dirname ($this->storagelock)); + if (!is_dir (dirname ($this->storagelock))) + throw new Exception ("Can't create '".dirname ($this->storagelock)."'", + 500); + $lockid = uniqid() . '_' . md5 (mt_rand()); + $startTime = microtime (TRUE); + // Stale lock : 60s old min + if (file_exists ($this->storagelock) && + filemtime ($this->storagelock) < time() - 60) + { + // TODO : Log the Stale lock removing + unlink ($this->storagelock); + } + + // Wait RW Lock + while (1) + { + while (file_exists ($this->storagelock)) + { + usleep (100000); + clearstatcache (TRUE, $this->storagelock); + if (microtime (TRUE) > $startTime + 10) + throw new Exception ("Can't have the authorization lock RW in 10s", + 500); + } + + file_put_contents ($this->storagelock, $lockid, FILE_APPEND); + clearstatcache (TRUE, $this->storagelock); + $cnt = file_get_contents ($this->storagelock); + if (substr ($cnt, 0, strlen ($lockid)) === $lockid) + break; + } + + // Wait all the RO lock to go away + $startTime = microtime (TRUE); + while (count (glob ($this->storagelock."-*")) > 0) + { + usleep (100000); + if (microtime (TRUE) > $startTime + 10) + throw new Exception ("Can't have the authorization lock RO in 10s", + 500); + } + + // I have the lock and no RO lock ! + return TRUE; + } + + /** This function lock the storage in share mode (to read the file without + modification at the same time) */ + public function lockRO () + { + if (!is_dir (dirname ($this->storagelock))) + @mkdir (dirname ($this->storagelock)); + if (!is_dir (dirname ($this->storagelock))) + throw new Exception ("Can't create '".dirname ($this->storagelock)."'", + 500); + $lockid = uniqid() . '_' . md5 (mt_rand()); + // Stale lock : 60s old min + if (file_exists ($this->storagelock) && + filemtime ($this->storagelock) < time() - 60) + { + // TODO : Log the Stale lock removing + unlink ($this->storagelock); + } + + // wait the removing of lockRW + $startTime = microtime (TRUE); + while (file_exists ($this->storagelock)) + { + usleep (100000); + clearstatcache (TRUE, $this->storagelock); + if (microtime (TRUE) > $startTime + 10) + throw new Exception ("Can't have the authorization lock in 10s", 500); + } + + touch ($this->storagelock."-".$lockid); + $this->storagelockRO = $this->storagelock."-".$lockid; + } + + /** This function unlock RW the storage file */ + public function unlockRW () + { + if (file_exists ($this->storagelock)) + unlink ($this->storagelock); + } + + /** This function unlock RO the storage file */ + public function unlockRO () + { + if ($this->storagelockRO !== FALSE && file_exists ($this->storagelockRO)) + unlink ($this->storagelockRO); + } +}