file locking question

B

bob

I am upgrading a server from a very old version of redhat to a new
version of debian. One of the things that needs to come along to the
new server is a web based perl program consisting of about 50 files. I
seem to have the majority of it working, but I have hit a snag.
there are a number of lines that contain syntax like this:

$filelock = do lock ("user/$userid.lck");
and a few lines later;
do unlock ($filelock)

Not being familiar with perl, from logs, documentation,and googling, I
arrived at this;
if I change the lines like so, it works;

flock("user/$userid.lck",2);
and a few lines later;
flock("user/$userid.lck",8);

So I set about writing a sed script to make all the changes, but then I
started to realized the scope of doing this over so many files, where
each file's $filelock variable often refers to a different file, and a
number of other variables like $userlock and $messagelock, most file's
variable having different values as well. its to the point where its
faster to manually decipher and change each file in the perl program
than try to write a script to do it with any relaiability.
The perl version on the old box is 5.6, so perhaps syntax for that
version simply won't work with the current 5.8.7 I have now. but there
must be an easier way to go about this other than changing each file or
writing a massive script - maybe there is a module I am not familiar
with, or some other configuration option I can use to just make the
original syntax work. At this point I am now striking out on google, I
was wondering if one of you experts would point me to some
documentation on this matter, or perhaps offer some ideas about a
direction I could take on this
 
G

Gunnar Hjalmarsson

I am upgrading a server from a very old version of redhat to a new
version of debian. One of the things that needs to come along to the
new server is a web based perl program consisting of about 50 files. I
seem to have the majority of it working, but I have hit a snag.
there are a number of lines that contain syntax like this:

$filelock = do lock ("user/$userid.lck");
and a few lines later;
do unlock ($filelock)

Not being familiar with perl, from logs, documentation,and googling, I
arrived at this;
if I change the lines like so, it works;

flock("user/$userid.lck",2);
and a few lines later;
flock("user/$userid.lck",8);

How did you reach the conclusion that the original code does not work on
the newer OS? Doesn't the program define the lock() and unlock() functions?
 
X

xhoster

I am upgrading a server from a very old version of redhat to a new
version of debian. One of the things that needs to come along to the
new server is a web based perl program consisting of about 50 files. I
seem to have the majority of it working, but I have hit a snag.
there are a number of lines that contain syntax like this:

$filelock = do lock ("user/$userid.lck");
and a few lines later;
do unlock ($filelock)


And what is the problem with it? Is the "weak" keyword by the same name
(lock) getting in the way? Have you accidentally taken out the code that
defined the lock and unlock subroutines?

Not being familiar with perl, from logs, documentation,and googling, I
arrived at this;
if I change the lines like so, it works;

flock("user/$userid.lck",2);
and a few lines later;
flock("user/$userid.lck",8);

That doesn't work for me, I get "Bad file descriptor"
So I set about writing a sed script to make all the changes, but then I
started to realized the scope of doing this over so many files, where
each file's $filelock variable often refers to a different file, and a
number of other variables like $userlock and $messagelock, most file's
variable having different values as well. its to the point where its
faster to manually decipher and change each file in the perl program
than try to write a script to do it with any relaiability.
The perl version on the old box is 5.6, so perhaps syntax for that
version simply won't work with the current 5.8.7 I have now. but there
must be an easier way to go about this other than changing each file or
writing a massive script - maybe there is a module I am not familiar
with, or some other configuration option I can use to just make the
original syntax work.

If you told us what was happening when you use this old syntax in your new
perl, I might be able to offer more help.


Xho
 
B

bob

Thank you both for your reply.
Valid questions,what I am doing and why I think its broken, I should
have included that at first, sorry...
first, let me say I am fairly certain I have apache and perl set up
properly, I arrive at that conclusion because by making the changes I
mentioned, I seem to be working, though I am quite discouraged doing
them all by hand.
The reason it was not working before is derived from information I
found in the apache2 error log, three entries, specifically:

[Sun Aug 28 11:26:00 2005] [error] [client 192.168.25.75] Can't modify
string in
lock at /var/www/computerisms/cgi-bin/ns/getpanel.pl line 21, near
""user/$PPid.lck
")", referer: http://192.168.25.200/
[Sun Aug 28 11:26:00 2005] [error] [client 192.168.25.75] Execution of
/var/www/
computerisms/cgi-bin/ns/getpanel.pl aborted due to compilation errors.,
referer: htt
p://192.168.25.200/
[Sun Aug 28 11:26:00 2005] [error] [client 192.168.25.75] Premature end
of scrip
t headers: getpanel.pl, referer: http://192.168.25.200/

In addition, the webpage comes up as internal server error and suggests
there will be answers in the logs.
the particular area of the file this error is talking about is here:

flock("user/$PPid.lck",2);
#$filelock = do lock ("user/$PPid.lck")

open (userfile, "<user/$PPid");
@userdata=<userfile>;
close (userfile);

foreach (@userdata)
{ if (substr ($_, -1) eq "\n") { chop; } };

flock("user/$PPid.lck",8);
#do unlock ($filelock)

when it comes to perl, I am no programmer, but my educated guess is
that the file needs to be locked while changes are made to it to
prevent more than one process from doing so at the same time. I tried
to find anything in google on "can't modify string in lock", and all
sorts of other things, and that led me to flock, and some experimenting
to what works.
But both of you seem to think I shouldn't be having this problem, or
perhaps I am approaching this from the wrong direction? any comments
appreciated :)
 
J

John W. Krahn

Valid questions,what I am doing and why I think its broken, I should
have included that at first, sorry...
first, let me say I am fairly certain I have apache and perl set up
properly, I arrive at that conclusion because by making the changes I
mentioned, I seem to be working, though I am quite discouraged doing
them all by hand.
The reason it was not working before is derived from information I
found in the apache2 error log, three entries, specifically:

[Sun Aug 28 11:26:00 2005] [error] [client 192.168.25.75] Can't modify
string in
lock at /var/www/computerisms/cgi-bin/ns/getpanel.pl line 21, near
""user/$PPid.lck
")", referer: http://192.168.25.200/

That error message (as well as all perl warning/error messages) is described
in the perldiag.pod file which should have been installed on your computer
when Perl was installed.

perldoc perldiag
[snip]
Can't modify %s in %s
(F) You aren't allowed to assign to the item indicated, or
otherwise try to change it, such as with an auto-increment.

[Sun Aug 28 11:26:00 2005] [error] [client 192.168.25.75] Execution of
/var/www/
computerisms/cgi-bin/ns/getpanel.pl aborted due to compilation errors.,
referer: htt
p://192.168.25.200/
[Sun Aug 28 11:26:00 2005] [error] [client 192.168.25.75] Premature end
of scrip
t headers: getpanel.pl, referer: http://192.168.25.200/

In addition, the webpage comes up as internal server error and suggests
there will be answers in the logs.
the particular area of the file this error is talking about is here:

flock("user/$PPid.lck",2);
#$filelock = do lock ("user/$PPid.lck")

open (userfile, "<user/$PPid");
@userdata=<userfile>;
close (userfile);

foreach (@userdata)
{ if (substr ($_, -1) eq "\n") { chop; } };

flock("user/$PPid.lck",8);
#do unlock ($filelock)

when it comes to perl, I am no programmer, but my educated guess is
that the file needs to be locked while changes are made to it to
prevent more than one process from doing so at the same time. I tried
to find anything in google on "can't modify string in lock", and all
sorts of other things, and that led me to flock, and some experimenting
to what works.

Have a look at the "File Locking" section in the perlopentut.pod document, as
well, perlfaq5.pod has some information on file locking.

perldoc perlopentut
perldoc perlfaq5



John
 
B

bob

Thanks John:
I have had a quick cursory glance, and it looks again like I will have
to change all the "do lock"s to flocks, but I will read the full
documentation to make sure. thanks again :)
 
X

xhoster

Thank you both for your reply.
Valid questions,what I am doing and why I think its broken, I should
have included that at first, sorry...
first, let me say I am fairly certain I have apache and perl set up
properly, I arrive at that conclusion because by making the changes I
mentioned, I seem to be working, though I am quite discouraged doing
them all by hand.
The reason it was not working before is derived from information I
found in the apache2 error log, three entries, specifically:

[Sun Aug 28 11:26:00 2005] [error] [client 192.168.25.75] Can't modify
string in
lock at /var/www/computerisms/cgi-bin/ns/getpanel.pl line 21, near
""user/$PPid.lck
")", referer: http://192.168.25.200/

It looks like you are getting hit by the relatively new keyword "lock",
which is used in threaded programs. It is a weak keyword, meaning that if
your program defines a subroutine named "lock" *before* your code tries to
call lock, then you it will call your subroutine. Otherwise, it calls the
built-in lock. I get the same error message when I call the built-in lock
with a string, they way you have.

Does your code define a lock subroutine? If so, is the subroutine defined
before your call to it?

Also, it seems that if you "use threads", then the built in "lock" always
gets called rather than your own lock routine.

when it comes to perl, I am no programmer, but my educated guess is
that the file needs to be locked while changes are made to it to
prevent more than one process from doing so at the same time. I tried
to find anything in google on "can't modify string in lock", and all
sorts of other things, and that led me to flock, and some experimenting
to what works.


This is a specific form of the generic "can't modify %s in %s".

But both of you seem to think I shouldn't be having this problem, or
perhaps I am approaching this from the wrong direction? any comments
appreciated :)

Using the "do" form of the subroutine call is unnecessary. It should
be fairly simple to eliminate the "do" semi-automatically, as none of the
rest of the syntax changes.

There must be a definition of the lock and unlock subroutines somewhere in
the old code. Find them. Make sure that these subroutines are defined in
the new code. Make sure that they are defined early in the script (to
avoid getting bit by the new "lock" keyword.) Alternatively, rename your
"lock" subroutine definition and all uses of it to something else, like
"old_lock". This should be fairly easy to do in a semi-automated way, as
you don't need to muck with either the argument list or the return value.


Xho
 
B

bob

thanks for sticking with this Xho, Sending a beer or coffee or whatever
into the karma pool for you....
Ok, so you say:
"Does your code define a lock subroutine? If so, is the subroutine
defined
before your call to it?", so I get to looking around.
there is a file called unixlock.pl, its contents are such:

# semaphores for Unix

# apply semaphore
sub lock
{
local ($aword)=@_;
open (locklock, ">$aword");
flock (locklock, 2);
*locklock;
}

# release semaphore
sub unlock
{
local (*locklock) = @_;
close (locklock);
}

now I don't really understand what all the special characters here are
referring to, but sub lock, that has to be the lock subroutine. in the
config.pl file, I find a line called "do unixlock.pl", and in all
files, at the very top is the line, "do config.pl". the answer
therefore must be yes, I have the subroutine lock defined, and its
definition is defined before the script requires its use. If I
understand correctly, this is as it should be.
you offer the alternative:
"Alternatively, rename your
"lock" subroutine definition and all uses of it to something else, like

"old_lock". This should be fairly easy to do in a semi-automated way,
as
you don't need to muck with either the argument list or the return
value."

so if I understand this right, in unixlock.pl, I should take:
sub lock (and probably sub unlock)
and change it to sub old_lock (and probably sub unold_lock)
then, I should take from my various .pl files, the lines like:
$filelock = do lock ("user/$userid.lck"); and change it to $filelock =
do old_lock ("user/$userid.lck");
and thus replacing the keyword problem
wow, I think I understand this.... I have to try it...
no, that gets me:
[Mon Aug 29 21:26:24 2005] [error] [client 192.168.25.75] Undefined
subroutine &
main::eek:ldlock called at /var/www/computerisms/cgi-bin/ns/getpanel.pl
line 21., refer
er: http://computerisms.ca/
Doh!
#sub lock
#sub old_lock
That won't work.

Voila :) uncomment that line, and I have joy!!!!
Xho, you are a genius! my many, many thanks...
 
A

A. Sinan Unur

(e-mail address removed) wrote in @f14g2000cwb.googlegroups.com:
thanks for sticking with this Xho, Sending a beer or coffee or
whatever into the karma pool for you....

[ Please quote some context when you reply ]

Ok, so you say:
"Does your code define a lock subroutine? If so, is the subroutine
defined before your call to it?", so I get to looking around.
there is a file called unixlock.pl, its contents are such:

# semaphores for Unix

use Fcntl ':flock';
# apply semaphore
sub lock
{
local ($aword)=@_;

my ($lock_fn) = @_;
open (locklock, ">$aword");

open my $lock_handle, '>', $lock_fn
or die "Cannot open $lock_fn: $!";
flock (locklock, 2);

flock $lock_handle, LOCK_EX
or die "Cannot lock handle on $lock_fn: $!";
*locklock;

return $lock)handle;
}

# release semaphore
sub unlock
{
local (*locklock) = @_;

my $lock_handle = @_;
close (locklock);

close $lock_handle
or die "Cannot close: $!";
}

now I don't really understand what all the special characters here are
referring to, but sub lock, that has to be the lock subroutine. in
the config.pl file, I find a line called "do unixlock.pl", and in all
files, at the very top is the line, "do config.pl".

AFAIK, those happen at run time, not at compile time. I would put the
subroutines in their own module, and 'use' the module at the top of the
program, and call the subroutine's with their fully qualified package
name. Or, just change the names of the subroutines to, say, obtain_lock
and release_lock, respectively.

See also:

<URL:http://www.stonehenge.com/merlyn/WebTechniques/col54.html>

Sinan
 
A

Anno Siegel

(e-mail address removed) wrote:
[...]

avoid getting bit by the new "lock" keyword.) Alternatively, rename your
"lock" subroutine definition and all uses of it to something else, like
"old_lock".

Rename it to "do_lock", then s/do lock/do_lock/g; That's economy! :)

Anno
 
X

xhoster

thanks for sticking with this Xho, Sending a beer or coffee or whatever
into the karma pool for you....

Thanks. <Homer Simpson> Coffee and Beer, Aaaarhhh </HS>

....
# semaphores for Unix

# apply semaphore
sub lock
{
local ($aword)=@_;
open (locklock, ">$aword");
flock (locklock, 2);
*locklock;
}

# release semaphore
sub unlock
{
local (*locklock) = @_;
close (locklock);
}

now I don't really understand what all the special characters here are
referring to, but sub lock, that has to be the lock subroutine.

The * is for dealing with typeglobs. This is a hold over from the good/bad
old days before lexical file handles (or, more accurately, filehandles were
automatically held in lexical variables, or something like that) were
supported.

It should also do error checking, so a more modern version would be:

sub lock
{
my ($aword)=@_;
open (my $locklock, ">", $aword) or die "Can't upen $aword: $!";
flock ($locklock, 2) or die "Can't lock $aword: $!";
return $locklock;
}

And the "2" in the flock should rather be the constant from the
Fcntl module. Of all the big hairy problems I've run into with file
locking, none of them has ever traced back to using the integers rather
than the constants to specify the lock mode, but still it is good practice
(and probably good karma) and all.

in the
config.pl file, I find a line called "do unixlock.pl", and in all
files, at the very top is the line, "do config.pl". the answer
therefore must be yes, I have the subroutine lock defined, and its
definition is defined before the script requires its use. If I
understand correctly, this is as it should be.

I must confess I don't know why it doesn't work. I never "do" files, I
always "use" or "require" them.
you offer the alternative:
"Alternatively, rename your
"lock" subroutine definition and all uses of it to something else, like

"old_lock". This should be fairly easy to do in a semi-automated way,
as
you don't need to muck with either the argument list or the return
value."

so if I understand this right, in unixlock.pl, I should take:
sub lock (and probably sub unlock)
and change it to sub old_lock (and probably sub unold_lock)
then, I should take from my various .pl files, the lines like:
$filelock = do lock ("user/$userid.lck"); and change it to $filelock =
do old_lock ("user/$userid.lck");
and thus replacing the keyword problem

You should also take out the "do" while you are at it, as it has been
deprecated for a long time. Who knows what problem that little word will
cause the *next* time you upgrade!

....

You're welcome.

Xho
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top