Directory locking in perl can be achieved by using the file locking construct flock().In the below code, only one thread can access the files contained in the directory. Once the first thread is finished, then only the other thread can start reading the contents of the directory.
use Fcntl ':flock';
chdir('orders');
open( FILE_LOCK, ">file.lock");
#Get exclusive lock on a lock file.Waits till the lock is acquired
if (flock FILE_LOCK, LOCK_EX) {
opendir(DIR, '.');
@dir_contents = readdir(DIR);
#Sleep will help you test the code. Run the same code on two different shells
sleep(5);
foreach $file (@dir_contents){
print $file."\n";
}
sleep(5);
}
close FILE_LOCK;
Thursday, October 16, 2008
Wednesday, October 15, 2008
DB Row locking without using inbuilt DB locks
I had come across a scenario where multiple threads would access the same row in the DB and would result in race condition. I was unable to use inbuilt lock as the mysql DB table was MyISAM. Also wanted a generic solution which could work for DBs with minimal locking mechanism.
The example is quite generic in nature and can be applied to any other language/DB.
The example is where multiple threads are trying to send the orders from the DB.
# Use process ID as our lock ID. Could really use any unique identifier.
$lock_id = getpid();
$lock_timestamp = time();
# "Claim" the orders that this process will attempt to re-upload, so that other
# processes cannot grab them - this prevents the race condition
sql("UPDATE order_table SET lock_id = $lock_id, lock_timestamp = $lock_timestamp WHERE lock_id IS NULL");
# Figure out which orders I was able to "claim"
$orders_to_retransmit = sql("SELECT * FROM order_table WHERE lock_id = $pid");
# ... process orders, if any were successful
# Clear locks - in case we still couldn't transmit, give a future process the opportunity
sql("UPDATE order_table SET lock_id = NULL WHERE lock_id = $pid");
# Extra: Clean up any abandoned locks from previous crashed runs
# (shouldn't happen but you never know)
sql("UPDATE order_table SET lock_id = NULL, lock_timestamp = NULL WHERE NOW() - lock_timestamp > 3600");
The example is quite generic in nature and can be applied to any other language/DB.
The example is where multiple threads are trying to send the orders from the DB.
# Use process ID as our lock ID. Could really use any unique identifier.
$lock_id = getpid();
$lock_timestamp = time();
# "Claim" the orders that this process will attempt to re-upload, so that other
# processes cannot grab them - this prevents the race condition
sql("UPDATE order_table SET lock_id = $lock_id, lock_timestamp = $lock_timestamp WHERE lock_id IS NULL");
# Figure out which orders I was able to "claim"
$orders_to_retransmit = sql("SELECT * FROM order_table WHERE lock_id = $pid");
# ... process orders, if any were successful
# Clear locks - in case we still couldn't transmit, give a future process the opportunity
sql("UPDATE order_table SET lock_id = NULL WHERE lock_id = $pid");
# Extra: Clean up any abandoned locks from previous crashed runs
# (shouldn't happen but you never know)
sql("UPDATE order_table SET lock_id = NULL, lock_timestamp = NULL WHERE NOW() - lock_timestamp > 3600");
Subscribe to:
Posts (Atom)