Solved

DBM File Locking (FLOCK) Problem...

Posted on 2000-04-26
5
233 Views
Last Modified: 2010-03-05
The following script is part of a login procedure.  When a user logs in, the script does the following...

If it is a new user, a counter field in a dbm is incremented and an entry is added to the same dbm containing the path to the user's record file.  The name of the record file is "rec#" (where # is the value of the counter).

The problem is that we are encountering circumstances where if two (or more) users log in at the same time (less than a second difference between each one pressing the "submit" button), the counter doesn't get incremented for each of the users.  When this happens, an entry is created for only one of the users, but the script returns the same record number (rec and counter) for all three.  We first implemented the flock control using O'Reilly's example with no success (we later found out that it causes a racing situation).  Our current script uses a "dummy" file for locking.  This improved the situation to its current status (<1 second causes error).  Please help!  The script follows:

#!/usr/bin/perl
use CGI qw(:standard);
use POSIX(O_CREAT,O_RDWR,O_RDONLY);
BEGIN { @AnyDBM_File::ISA = qw(DB_File GDBM_File) }
use AnyDBM_File;


$myLock_SH = 1;
$myLock_EX = 2;
$myLock_NB = 4;
$myLock_UN = 8;


#path to name/record list file
my $caseRef = param("caseRef");
my $tmp = '';
until ($tmp eq '/') {
      $tmp = chop($caseRef);
}
substr($caseRef,0,1) = "";
$caseRef =~ s/DxR\///g;

my ($dir,$regName,$longCaseRef,$usrPW,$lockFileFlag,%usrArray,$usrArray,%recArray,$recArray,$nextFile);

      $longCaseRef = $caseRef;
      $regName = $caseRef.'/caseRec/dxr_stor';
      $lockFileFlag = $caseRef.'/caseRec/intList.txt';

my $usrName = param("dxrUser");
my $enteredPW = param("dxrPassword");
chomp $enteredPW;

my $tError = 'OK';
my $hypCount = 0;


####### open pat database file

###local *myLock;
      # Wait until database is available
                  unless ( open(myLock, ">$lockFileFlag") ) {
                        $tError = "Open lock file error  $! ";
                  }
                  unless ( flock(myLock, 2) ) {
                        $tError = "lock error  $!";
                  }
      
                  
unless (tie(%usrArray,AnyDBM_File,$regName,O_RDWR,0666)) {
  $tError =  "Name/Record List file not found. <br> $!";
}

#is file initialized
if ($tError eq 'OK') {

            
######check password
      if ($usrPW = $usrArray{$usrName . 'pw'}) {
            chomp $usrPW;
            if ("$usrPW" ne "$enteredPW") {
                  $tError =  "Password not correct." ;
            }
      } else {
                  $tError =  "Name not found." ;
      }
}
if ($tError eq 'OK') {
      if ($usrFile = $usrArray{$usrName}) {
            
            untie(%usrArray);
            close(myLock);
            
            #record of file exists open and get variables?
            if(tie(%recArray,AnyDBM_File,$usrFile,O_RDWR,0666)) {
                  $hypCount = $recArray{'hypCount'};
                  untie(%recArray);
            } else {
                  $tError =  "Record file not opened. <br> $!";
            }
      } else {
            #start file
                  
            $nextFile = $usrArray{'nextFile'};
            $usrFile = $longCaseRef."/caseRec/rec" . $nextFile;
            $usrArray{$usrName} = $usrFile;
            $usrArray{'nextFile'} += 1;
            
            untie(%usrArray);
            close(myLock);
            
            
            if(tie(%recArray,AnyDBM_File,$usrFile,O_RDWR|O_CREAT,0666)) {
                  $recArray{'hypCount'} = $hypCount;
                  untie(%recArray);
            } else {
                  $tError =  "Record file not created. <br> $!";
            }
      }
}
#output hyp html page

print <<END_Hyp;
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
<title>Log Result</title>

</head>
<body bgcolor="#E6D6BD" >
User: $usrName <BR>
Status: $tError <BR>
User Storage: $regName <BR>
Case Path: $caseRef <BR>
User Record: $usrFile <BR>$$  <BR>$txError

</body>
</html>

END_Hyp

exit;
0
Comment
Question by:rhej
  • 3
  • 2
5 Comments
 
LVL 84

Expert Comment

by:ozo
Comment Utility
The lock is released when you close the lock file, and you're updating %usrArray and %recArray after the close.
0
 

Author Comment

by:rhej
Comment Utility
I agree that the lock is closed before the modifications to recArray are complete (we don't lock this array because it is user specific and should never encounter a multiuser scenario), but the usrArray was untied before the lock was closed and was not updated afterward.  Please let me know if I am incorrect in this assumption.

Please note that both of the untie and close statements for usrArray are within an if/else statement (I apologize for the lack of indentation.  Didn't paste properly...).
0
 
LVL 84

Accepted Solution

by:
ozo earned 200 total points
Comment Utility
you're right, I missed the unindented separate cases for the close.
But I'm now puzzled that$hypCount only seems to be set in one branch, and only used in the other?
I'm also concerned that bad values in param("caseRef") might cause a failure.
Do you ever see anything in $tError?
Do you know if AnyDBM_File is using DB_File or GDBM_File?
Do either of them need to flush after an untie?
Could you try adding sleep 30; before the close(myLock);
just to verify that it really is blocking?
0
 

Author Comment

by:rhej
Comment Utility
The script posted is not the complete script.  For space reasons I only posted the parts that used usrArray and flock.  $hypCount refers to some of the missing portions and is actually implemented in both branches.  caseRef is also error trapped in the complete script.
The only times we have ever seen error messages from $tError have been permissions problems (script didn't have write access).
AnyDBM_File appears to be using DB_File on our testing box.  I do not know whether they need to flush.  Finding definitive information on them has been somewhat arduous.
I believe a sleep (60) has been implemented to test this, but I need to double check with the author (it's not my script).  I know that I recommended such a test, I'm just not sure he did it.  I will check and let you know.
0
 

Author Comment

by:rhej
Comment Utility
Thanks for the assistance!  It appears to have been a flushing (sync) problem.  Implementing a sync command for the tied dbm before unlocking the lock file appears to have fixed the problem.

Thanks!
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

On Microsoft Windows, if  when you click or type the name of a .pl file, you get an error "is not recognized as an internal or external command, operable program or batch file", then this means you do not have the .pl file extension associated with …
Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now