* @license BSD */ namespace Domframework; /** 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) . "' directory for lockfile", 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); } } }