Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Jan 11th, 2008, 4:30 PM   #1
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
File Locking without using flock

Any ideas?
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Jan 11th, 2008, 7:00 PM   #2
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5 grumpy is on a distinguished road
Re: File Locking without using flock

Depends what you're trying to achieve.

One option would be to generate a temporary file name using a process that guarantees a unique name so it is only known to the process/script that generates it. Then rename/move the file you want to that temporary location. The file is effectively locked, as (in the eyes of any other processes) it no longer exists. Then do all your work on the temporary file. When the work is done rename/move the temporary file back to the original location. Depending on needs of the application, check if the original file has been recreated while work has been done on the temporary file -- and respond in a manner that makes sense to your script (eg append the original file to the temporary and delete it before copying the whole lot back, etc)

Another option is to use specific features of your operating system to enforce locks in different ways. The trade-off there is that the script is no longer portable.

Yet another option is to implement your system in a client/server arrangement, and (as far as your script is concerned) do without files completely. The script communicates with some back-end server (eg a database) which mediates access to the data via (say) a transactional approach.
grumpy is offline   Reply With Quote
Old Jan 13th, 2008, 2:49 PM   #3
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Re: File Locking without using flock

The second and third option would not be viable as my forum script needs to remain portable and no client/server communication is necessary. What I'm trying to achieve is a database that locks files so as to prevent accidental overwriting.

This is what I understood in a stepwise fashion:
  1. generate a temporary unique filename in the location of interest
  2. move said file to another temporary location
  3. work on temporary file in temporary location
  4. move temporary file back to location of interest
  5. analyze original file and determine what to do with temporary file
I'm not so sure I'd know where to begin in order to generate a unique filename, it would seem to me that if they're just randomly generated without any inter-dependancy then they might collide. Something like rfc4122 uuids for instance.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Jan 13th, 2008, 4:43 PM   #4
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5 grumpy is on a distinguished road
Re: File Locking without using flock

Yes, randomly generated names can clash. One way to reduce likelihood is to check the existence of the randomly named file and, if it exists, generate another name. There are many ways to generate random names; I'll leave learning such things as an exercise.

Also, look up the tempnam() function. Names generated are not necessarily random, but they are specified as unique.

Your requirement for portability and guaranteed file locking, in general, are mutually exclusive. True file locking (preventing access by anything except the creator) relies on support of the host operating system, so always inherently has some element of non-portability (and not all systems can do it).

Why, if you are essentially looking for database-like behaviour, is it not suitable to use a database back end? There are a number of portable (or, more correctly, multiplatform) database products around.
grumpy is offline   Reply With Quote
Old Jan 13th, 2008, 5:47 PM   #5
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Re: File Locking without using flock

I'm trying to develop a database backend using flat files ^_^. At the moment I believe my database creates files which will never overwrite one another. However, I just want to check other options available as perhaps one will appear as superior.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Jan 13th, 2008, 5:53 PM   #6
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Re: File Locking without using flock

Dude that tempnam function is sweet grumpy that seems to be exactly what I was looking for. Now I just need to figure out a way to rename the files without accidentally overwriting another one.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Jan 14th, 2008, 5:26 PM   #7
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Re: File Locking without using flock

This is the solution I came up with thx to grumpy's suggestions and some research into mutex and such to get a lock on a file without actually using the flock function.
function mutexAcquireLock($filename, $timeout){
	$fp = @fopen($filename . '.lck', 'x');
	if($fp === false) return false;
	if(false === @fwrite($fp, time() + $timeout)) return false;
	return fclose($fp);
}

function mutexReleaseLock($filename){
	return @unlink($filename . '.lck');
}
This always functions as an exclusive writer lock. I haven't actually tested it with multiple executions of the same script so I'll post up here how I tested it and what happened once I do.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Jan 14th, 2008, 6:14 PM   #8
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Re: File Locking without using flock

Here were the results of two simultaneous scripts (mutex.php and tester.php) running on windows attempting to lock the file mutex.php
mutex.php results
Quote:
2524: Lock acquired -> Lock released
2524: Lock acquired -> Lock released
2524: Lock acquired -> Lock released
2524: Lock acquired -> Lock released
2524: Lock acquired -> Lock released
2524: Lock acquired -> Lock released
2524: Failed lock
2524: Failed lock
2524: Failed lock
2524: Lock acquired -> Lock released
tester.php results
Quote:
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> 5820: Lock failed -> Lock forcibly removed
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
5820: Lock acquired -> Lock released
What happened here is that the first script executes a for loop 10 times and the second script executes a for loop 20 times, but the loops in the first sleep for 2 seconds and the loops in the second sleep for 1 second. In the second script an intentional error is caused on the 11th iteration of the loop and the program sleeps for 5 seconds so as to give the lock some persistence. Furthermore, the second script has the ability to check the timeout of the lock and forcibly release it if the time has lapsed. Here's the source:
mutex.php
<?php
for($i = 0; $i < 10; $i++){
	fwrite(STDOUT, getmypid() . ": ");
	if(!mutexAcquireLock('mutex.php', 2)){
		fwrite(STDOUT, "Failed lock\n");
		sleep(2);
	}else{
		fwrite(STDOUT, "Lock acquired -> ");
		if(!mutexReleaseLock('mutex.php')){
			fwrite(STDOUT, "File not locked" . "\n");
		}else{
			fwrite(STDOUT, "Lock released" . "\n");
		}
		sleep(2);
	}
}

function mutexAcquireLock($filename, $timeout){
	$fp = @fopen($filename . '.lck', 'x');
	if($fp === false) return false;
	if(false === @fwrite($fp, time() + $timeout)) return false;
	return fclose($fp);
}

function mutexReleaseLock($filename){
	return @unlink($filename . '.lck');
}
?>
tester.php
<?php
for($i = 0; $i < 20; $i++){
	fwrite(STDOUT, getmypid() . ": ");
	if(!mutexAcquireLock('mutex.php', 2)){
		fwrite(STDOUT, "Lock failed -> ");
		$tiempo = mutexTimeOut('mutex.php');
		if($tiempo !== false && $tiempo < 0){
			if(!mutexReleaseLock('mutex.php')){
				fwrite(STDOUT, "Unable to forcibly remove lock" . "\n");
			}else{
				fwrite(STDOUT, "Lock forcibly removed" . "\n");
			}
		}
		sleep(1);
	}else{
		fwrite(STDOUT, "Lock acquired -> ");
		if($i != 10){
			if(!mutexReleaseLock('mutex.php')){
				fwrite(STDOUT, "File not locked" . "\n");
			}else{
				fwrite(STDOUT, "Lock released" . "\n");
			}
		}else{
			sleep(5);
		}
		sleep(1);
	}
}

function mutexAcquireLock($filename, $timeout){
	$fp = @fopen($filename . '.lck', 'x');
	if($fp === false) return false;
	if(!@chmod($filename . '.lck', 0755)) return false;
	if(false === @fwrite($fp, time() + $timeout)) return false;
	return fclose($fp);
}

function mutexReleaseLock($filename){
	return @unlink($filename . '.lck');
}

function mutexTimeOut($filename){
	$timeout = @file_get_contents($filename . '.lck');
	if($timeout === false) return false;
	return intval($timeout) - time();
}
?>
Seems to work well, but perhaps I'm missing something. If anyone can point out where it might fail I'd appreciate the input.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Jan 15th, 2008, 1:38 PM   #9
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 403
Rep Power: 3 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Re: File Locking without using flock

I did realize there would be one flaw where if the system hanged, it's possible that another script could override the lock, then the process that was hanging could reengage and overwrite as it deems that it never released the lock. In order to compensate for that I made the timeout a factor of multiplication rather than a time given. This factor now multiplies the maximum script execution time as determined by your server's PHP settings. I also worked it into a class definition.
PHP Syntax (Toggle Plain Text)
  1. <?php
  2. error_reporting(E_ALL);
  3.  
  4. /* Reference Material
  5.  *
  6.  * http://en.wikipedia.org/wiki/ACID
  7.  *
  8.  */
  9.  
  10. class Mutex {
  11. /* Private variables */
  12.  
  13. var $filename; // The file to be locked
  14. var $timeout; // The timeout value of the lock
  15. var $permission = 0755; // The permission value of the locked file
  16.  
  17. /* Constructor */
  18.  
  19. function Mutex($filename, $timeout = 1, $permission = null){
  20. // Append '.lck' extension to filename for the locking mechanism
  21. $this->filename = $filename . '.lck';
  22. // Timeout should be some factor greater than the maximum script execution time
  23. if($timeout < 1) $this->timeout = get_cfg_var('max_execution_time');
  24. else $this->timeout = $timeout * get_cfg_var('max_execution_time');
  25. // Should some other permission value be necessary
  26. if(isset($permission)) $this->permission = $permission;
  27. }
  28.  
  29. /* Methods */
  30.  
  31. function acquireLock(){
  32. // Create the locked file, the 'x' parameter is used to detect a preexisting lock
  33. $fp = @fopen($this->filename, 'x');
  34. // If an error occurs fail lock
  35. if($fp === false) return false;
  36. // If the permission set is unsuccessful fail lock
  37. if(!@chmod($this->filename, $this->permission)) return false;
  38. // If unable to write the timeout value fail lock
  39. if(false === @fwrite($fp, time() + intval($this->timeout))) return false;
  40. // If lock is successfully closed validate lock
  41. return fclose($fp);
  42. }
  43.  
  44. function releaseLock(){
  45. // Delete the file with the extension '.lck'
  46. return @unlink($this->filename);
  47. }
  48.  
  49. function timeLock(){
  50. // Retrieve the contents of the lock file
  51. $timeout = @file_get_contents($this->filename);
  52. // If no contents retrieved return error
  53. if($timeout === false) return false;
  54. // Return the timeout value
  55. return intval($timeout);
  56. }
  57. }
  58. ?>
Now if the process should hang PHP should take care of stopping it from writing, and another process can override the lock safely.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis

Last edited by grimpirate; Jan 15th, 2008 at 1:56 PM.
grimpirate is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
problem processing file into a char array csrocker101 C++ 1 May 8th, 2007 11:50 PM
add mutiple users to the smbpasswd file. Pizentios Bash / Shell Scripting 3 Oct 20th, 2005 12:48 PM
After execution - Error cannot locate /Skin File? wchar Visual Basic 1 Mar 5th, 2005 9:04 PM
airport Log program using 3D linked List : problem reading from file gemini_shooter C++ 0 Mar 2nd, 2005 4:12 PM
Structure char field to a disk file ehab_aziz2001 C++ 0 Feb 10th, 2005 2:42 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 1:01 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC