brendonc has asked for the wisdom of the Perl Monks concerning the following question:
Hello all
I have sort of a weird question. It's probably obvious, but I
just need clarification. Say if I have a small script that
is split up into subroutines and the program is run by calling
those subs like:
split_logfile();
gen_stats();
compress_logs();
clean_up();
Correct me if I'm wrong, but won't Perl execute the sub
split_logfile() and when it's finished, execute gen_stats(),
and so on? It seems like when I run the script, split_logfile
doesn't complete before gen_stats gets run, which breaks everything.
But, if I just run split_logfile() it works perfectly. It's almost
as if all the subroutines are executed at the same time...
If anyone can help clarify this I'd be quite grateful.
Thanks
Brendon
Re: Calling functions
by one4k4 (Hermit) on Mar 23, 2001 at 02:03 UTC
|
You may want to post the code to your script. If sub split_logfile{} doesnt do much, then it may be run without you even noticing. Unless you're printing something during that sub.
Try something like this... (In case you havent already):
sub split_logfile(){
print "In sub split_logfile\n";
}
sub gen_stats(){
print "In sub gen_stats\n";
}
sub compress_logs(){
print "In sub compress_logs\n";
}
sub clean_up(){
print "In sub clean_up\n";
}
You get the idea. Granted, like the others have said, if you're calling external programs, they may be running in the background....
_14k4 - webmaster@860.org (www.poorheart.com)
| [reply] [d/l] [select] |
|
print("DONE\n");
At the end of split_logfile() and
print("Starting gen_stats\n");
at the beginning of gen_stats(). It printed the messages out
in correct order:
DONE
Starting gen_stats
...
So it appears that the functions are getting called in the
correct order. | [reply] [d/l] [select] |
Re: Calling functions
by DeusVult (Scribe) on Mar 23, 2001 at 02:16 UTC
|
Without more info, I can't give you a specific answer, but always remember that the order things look like they're getting executed in isn't always the order they are exectuted in. Remember that as a general computer principle, calculation happens much, much faster than I/O. So if you're judging the order of execution by looking at the output of print statements or something like that, you may be deceived, especially if some input is going to STDOUT, some to STDERR, some to files, etc.
The reason this can happen is that the I/O is processed, and then left for the OS to pick up and display. In the mean time, the computer sees no need to just wait around twiddling it thumbs, so it goes on and executes the next line of code. It may very well be able to execute several of lines of code (depending on their complexity/operations) in the time it takes to do a single print statement. But if one of those lines in turn sends something to STDERR, then that could end up getting shunted to the front of the I/O list, because STDERR is given higher priority than STDOUT on most platforms.
So if you have the lines:
print "Hello there\n";
print STDERR "My name is bob\n";
There is no guarantee which line will be printed first. Usually "hello there" will make it to the screen first, but there is no guarantee of that (unless perl does something behind the scenes that I'm not aware of).
And screen I/O is faster than file I/O, so if you've also got output to a file that you're tail -f'ing, that can appear all out of order, too.
Of course, this could all be completely unrelated to your problem, but I hope it helps (or was at least mildly educational).
Some people drink from the fountain of knowledge, others just gargle. | [reply] [d/l] [select] |
Re: Calling functions
by c-era (Curate) on Mar 23, 2001 at 01:55 UTC
|
If split_log calls another program, it is posible you started that program in the background. Your perl script will continue executing even though the program you called hasn't finished. | [reply] |
Re: Calling functions
by AgentM (Curate) on Mar 23, 2001 at 01:52 UTC
|
"That's impossible."
Seriously, perhaps you simply didn't finish processing the data before moving on to the next function? These functions are executed sequentially.
AgentM Systems nor Nasca Enterprises nor
Bone::Easy nor Macperl is responsible for the
comments made by
AgentM. Remember, you can build any logical system with NOR.
| [reply] |
Re: Calling functions
by busunsl (Vicar) on Mar 23, 2001 at 01:53 UTC
|
Perl normally executes the subs in the given order.
But that depends on what you are doing in those subs.
So if your program is small, just post it completely, otherwise post a bit more of your program and of the subs.
Or, even better, post a url where it can be seen completely. | [reply] |
Re: Calling functions
by brendonc (Novice) on Mar 23, 2001 at 02:20 UTC
|
Well here's the split_logs() function (this is code that I copied/
modified from the splitlogs script that is included in the Apache
source):
sub split_logfile {
# As adapted from the split-logile perl script from the Apache gro
+up
my($vhost);
my($log_line);
my(%is_open);
open(LOG, "<$access_log")
or die("Cannot open $access_log for processing: $!");
while($log_line = <LOG>) {
($vhost) = split(/\s/, $log_line);
$vhost = lc($vhost);
if (! $is_open{$vhost}) {
open $vhost, ">>$work_dir/${vhost}.log"
or die ("Cannot open ${vhost}.log: $!");
$is_open{$vhost} = 1;
}
$log_line =~ s/^\S*\s+//;
printf($vhost "%s", $log_line);
}
print("DONE\n");
}
It works properly every time, that is, if it is run apart from
the proceeding functions. Here is gen_stats():
sub gen_stats {
my($log);
my($domain);
# Generate stats for the entire server (server wide)
system($webalizer, "-q", "-D", $work_dir."/dns_cache.db", "-N", "2
+0", "-n", $server_hostname,
"-o", $server_log_dir, $access_log);
opendir(WORKDIR, $work_dir) or die "Could not open $work_dir: $!\n
+";
while (defined($log = readdir(WORKDIR))) {
# If the file isn't . or .. then strip off the .log portion to
+ get just the host
# + domain. Run webalizer using log file.
if ($log !~ /^\.\.?$/ and $log !~ /dns_cache\.db/) {
($domain) = split(/\.log/, $log);
# IF the web stats directory doesn't exist, don't bother r
+unning stats for
# that particular web.
if ( -e "$stats_dir/$domain" ) {
system($webalizer, "-q", "-D", $work_dir."/dns_cache.d
+b", "-N", "20",
"-n", $domain, "-o", $stats_dir."/".$domain, $work
+_dir."/".$log);
} else { print "Stats directory for $domain doesn't exist.
+\n"; }
}
}
closedir WORKDIR;
}
The files that split_logfile() creates when it's run alone must have
at least one log entry in them or they're simply not created.
If I run it in conjunction with gen_stats(), several files
are created without a single entry in them (zero length, as though the function simply doesn't finish). I've looked it over
several times, yet I cannot seem to figure it out. If it's something
simple or I'm doing something wrong, please keep in mind
that I am a Perl beginner. :)
Thanks again.
Brendon
| [reply] [d/l] [select] |
|
close $vhost or warn "Failure closing $vhost: $!\n";
-
tye
(but my friends call me "Tye") | [reply] [d/l] |
|
I don't know exactly what your code if doing, but is gen_stats is trying to read a file split_logfile is creating, you might be running into a buffering problem.
Try putting this line at the beginning of split_logfile:
local $| = 1;
This will turn autoflush on, which means Perl will output to a file immediately after a print, rathering than saving outputs up and doing them all at once.
| [reply] [d/l] |
|
| [reply] |
Re: Calling functions
by brendonc (Novice) on Mar 23, 2001 at 04:06 UTC
|
Ok so I've set it so that Perl will flush after every write.
I've also added another loop in split_logfile() to close every
file (perhaps it wasn't finished writing to the files before it
moved on to gen_stats()?). But, this has no effect. I still have
several random files that are zero length, as if the log entries
are not being written at all. Oddly enough, there are several
files that appear to be written correctly. I just don't get it... | [reply] |
|
What platform are you on?
On Windows when dealing with shared filesystems I have
been burned enough that I routinely make sure that I have
waited a substantial time (eg one second) between when I
closed a file and when I do anything which depends on my
write being visible to the world. Why this should be
necessary I do not know, but then again I likewise don't
bother to remember the exact combination of versions of
Perl and Windows in which renaming a file from FOO to foo
will delete the file because it does not realize that the
target is the original file. (So delete the existing, then
go to ren...oops.)
I merely know that I was burned and the absolutely safe
fixes were to sleep in the one case or in the other to
rename into another directory and then rename back.
(Contrary to Microsoft's documentation on the bug,
renaming through another name in the same directory was
not safe.)
Anyways it is possible that you are hitting bugs...
| [reply] |
|
| [reply] |
|
|