note 74391 added to function.flock

From: Date: Mon, 09 Apr 2007 19:37:40 +0000
Subject: note 74391 added to function.flock
Groups: php.notes 
Request: Send a blank email to php-notes+get-125240@lists.php.net to get a copy of this message
Hi, The discussions below address flock() in the context of managing integrity of file contents as well as the context of using flock() in combination with a dummy file to generally establish agreement on the access state of some other object. The following addresses the latter. I use this as a replacement for LOCK TABLES because during some transactional update statements I require the contents of other tables to freeze and transactions and tablelocks don't mix in mySQL / InnoDB. <?php class ReadWriteLock { const LOCK_PATH = "locks"; public static function Aquire($ID, $LockType = LOCK_SH, $WouldBlock = TRUE) { // Make sure the file exists and we have it opened. // We don't care about writing to the file. We just need a file reference that flock() can work on. // Also, on an OS level all thread's are sharing this file. We don't do access control in relation to this file. // So let's assume first that it already exists. $FileName = self::LOCK_PATH."/lock_$ID.lck"; if(($Resource = @fopen($FileName, "r")) === FALSE) // Ok, so this is the first time a thread acquires a lock to this $ID. Let's create the file. if(($Resource = @fopen($FileName, "w")) === FALSE) { // Ok, perhaps some thread created it between the two ifs. This class does not delete the file so it should now be there. if(($Resource = @fopen($FileName, "r")) === FALSE) return FALSE; } else { // #REF 1 // Ok, it exists now. Just for solidarity and prevention of whatever OS hickups we can possibly have // I want this thread to open it in r mode too. if(fclose($Resource) === FALSE) return FALSE; if(($Resource = @fopen($FileName, "r")) === FALSE) return FALSE; } // And this is really where the locking takes place. if(flock($Resource, $LockType, $WouldBlock)) return $Resource; fclose($Resource); return FALSE; } public static function Release($Resource) { if(fclose($Resource)) return TRUE; return FALSE; } } // Entering critical section if(($Lock = ReadWriteLock::Acquire("metadata")) === FALSE) die("Failed to either create or acquire the lock.") // Construct SQL statements from meta tables // Execute constructed SQL statements agains data tables // Leaving critical section if((ReadWriteLock::Release($Lock)) === FALSE) die("Failed to release the lock."); ?> A few notes about this: - As you can see, this just creates 'a' file to use as a reference for flock() to work on. My assumption here is that the operating system uses semaphores internally to implement Flock(). Of that, I am not sure however and I would appreciate any validation from an expert. - The problem of the existence of the lockfile is solved by simply not deleting them. Given that they are all 0-byte files in a specified folder and that they are only of a limited amount makes it something that works for my solution. Alternatively you could touch() the lockfile upon a succesful flock() and use a cron job to delete any files that have not been touched since, say, a day (or at least for the duration of the session timeout setting of your webserver). That would introduce a race condition for access on the actual file though which I prefer to exclude from the above. - flock() implements a low priority exclusive lock. This means that once the resource is locked in a shared mode, exclusive locks may be delayed indefinately if (and only if) a continuous abundance of shared lock requests come in so that every thread releases his shared lock after another thread has already gained shared access. For me, this is an ussue and I would appreciate any references to establish a high priority exclusive lock. Good luck, Juice ...Tastes like more! ---- Server IP: 83.137.20.120 Probable Submitter: 85.144.164.25 ---- Manual Page -- http://www.php.net/manual/en/function.flock.php Edit -- https://master.php.net/note/edit/74391 Del: integrated -- https://master.php.net/note/delete/74391/integrated Del: useless -- https://master.php.net/note/delete/74391/useless Del: bad code -- https://master.php.net/note/delete/74391/bad+code Del: spam -- https://master.php.net/note/delete/74391/spam Del: non-english -- https://master.php.net/note/delete/74391/non-english Del: in docs -- https://master.php.net/note/delete/74391/in+docs Del: other reasons-- https://master.php.net/note/delete/74391 Reject -- https://master.php.net/note/reject/74391 Search -- https://master.php.net/manage/user-notes.php

« previous php.notes (#125240) next »