Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Calling functions

by brendonc (Novice)
on Mar 23, 2001 at 01:47 UTC ( [id://66473]=perlquestion: print w/replies, xml ) Need Help??

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

Replies are listed 'Best First'.
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)
      Right. I put
      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.
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.

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.
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.
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.

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

      close $vhost or warn "Failure closing $vhost: $!\n";
              - tye (but my friends call me "Tye")
      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.

        That would only autoflush STDOUT, which probably isn't the problem in this case.

                - tye (but my friends call me "Tye")
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...
      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...

      I must have overlooked something. I did some further testing, and it appears that if I don't close the files that I've opened then the data does not get fully written to them. I should have known this... but in the original script from the Apache source it didn't do this - probably because it only had one routine to do and then the script ended, closing all the files automatically.

      Thanks to all for the help!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://66473]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (2)
As of 2024-04-19 21:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found