can you flock a file or lock a file before opening it.

Discussion in 'Perl Misc' started by John Smith, Dec 1, 2003.

  1. John Smith

    John Smith Guest

    I want to ensure that only one person at a time can edit a file using my
    perl script.

    From what I've read, it appears that you can only flock a file after opening
    it.
    So I guess it would look like this:

    - open the file for writing
    - flock the file for exclusive (2)
    - update the file
    - unflock the file or flock (8)
    - close the file

    I'm suspecting that if the file is already open when you try to flock it,
    the flock function will return an error code?


    Now this would work great if you are trying to append to a file, as in a log
    file, but what if you want to change info in the file? Maybe I'm not doing
    this properly.

    - My program opens (for read), reads the entire file, and closes the file.
    - Then it open (for write), re-writes the complete file (with the updates),
    and closes the file.


    From what I understand, if I can't lock the file before opening it, then
    this flock won't help me.


    Now it turns out that my perl script will be the only program accessing
    these files.
    So I thought, that maybe I could have a dummy file that I would flock. If I
    can flock this file, then I would allow my perl program to read, delete,
    re-write or whatever to my other data files. Once I'm done, I unflock the
    dummy file.


    Another question... My perl script runs on a web server and when it is
    called, it does a few quick things and terminates. When the perl script
    terminates, will all files locked by the perl script be unlocked upon
    termination (in the event that an error occured and it ended prematurely -
    not that it would).


    I think I was told that the web server is running perl 5.8???
    This brings me to a final question.
    Is there a function that can retrieve the version of Perl that is running?
    This would be nice since the server is like 3 hours away (200 miles away!)


    Thanks for all.
    G.Doucet
    John Smith, Dec 1, 2003
    #1
    1. Advertising

  2. On Mon, 01 Dec 2003 04:28:47 GMT, "John Smith" <> wrote:

    >I want to ensure that only one person at a time can edit a file using my
    >perl script.
    >
    >From what I've read, it appears that you can only flock a file after opening
    >it.
    >So I guess it would look like this:
    >
    > - open the file for writing
    > - flock the file for exclusive (2)
    > - update the file
    > - unflock the file or flock (8)
    > - close the file
    >
    >I'm suspecting that if the file is already open when you try to flock it,
    >the flock function will return an error code?


    If the file is already locked, the program will either wait for the lock to be
    released or will return an error. This depends on the second argument to flock.
    See the docs in perlfunc:
    ===
    OPERATION is one of LOCK_SH, LOCK_EX, or LOCK_UN, possibly combined with
    LOCK_NB. These constants are traditionally valued 1, 2, 8 and 4, but you can
    use the symbolic names if you import them from the Fcntl module, either
    individually, or as a group using the ':flock' tag. LOCK_SH requests a shared
    lock, LOCK_EX requests an exclusive lock, and LOCK_UN releases a previously
    requested lock. If LOCK_NB is bitwise-or'ed with LOCK_SH or LOCK_EX then flock
    will return immediately rather than blocking waiting for the lock (check the
    return status to see if you got it).
    ===

    >So I thought, that maybe I could have a dummy file that I would flock. If I
    >can flock this file, then I would allow my perl program to read, delete,
    >re-write or whatever to my other data files. Once I'm done, I unflock the
    >dummy file.


    I use this in one script that writes its log entries to a db file (don't ask
    why :)). Here's a code excerpt:

    dblogflock();
    tie(%lastogin, 'DB_File', $login_db) or mydie('Cannot tie login DB',
    __LINE__);
    $lastlogin{$user} = time;
    untie %logins;
    undblogflock();

    sub dblogflock {
    open(LDBM, ">$loglockfile") or mydie("loglockfile error: $!", __LINE__);
    flock LDBM, 2;
    }

    sub undblogflock {
    close LDBM;
    }

    Note that this will wait until the other process releases the lock before it
    completes.

    ---
    Use the domain skylightview (dot) com for the reply address instead.
    William Herrera, Dec 1, 2003
    #2
    1. Advertising

  3. "John Smith" <> writes:

    [ Unless you have permission from Microsoft to use their domain in
    your mail address then doing so is rude to say the least (and probably
    actionable). ]

    > I want to ensure that only one person at a time can edit a file using my
    > perl script.
    >
    > From what I've read, it appears that you can only flock a file after opening
    > it.
    > So I guess it would look like this:
    >
    > - open the file for writing
    > - flock the file for exclusive (2)
    > - update the file
    > - unflock the file or flock (8)
    > - close the file
    >
    > I'm suspecting that if the file is already open when you try to flock it,
    > the flock function will return an error code?


    Just being open will not interact with locking unless you have
    mandatory locking configured on the file at the OS level.

    flock() will block rather than return a failure code unless to
    explicitly ask for non-blocking mode.

    > - My program opens (for read), reads the entire file, and closes the file.
    > - Then it open (for write), re-writes the complete file (with the updates),
    > and closes the file.
    >
    > From what I understand, if I can't lock the file before opening it, then
    > this flock won't help me.


    So open the file read/write in the first place then you don't need to
    close it and can hold the lock throughout.

    > So I thought, that maybe I could have a dummy file that I would flock. If I
    > can flock this file, then I would allow my perl program to read, delete,
    > re-write or whatever to my other data files. Once I'm done, I unflock the
    > dummy file.


    That too, is a valid approach.

    Be aware that to cope gracefully with abnormal termination one usually
    would write the updated file to a new file then rename that file over
    the old one. This trick would need to combined with the
    aforementioned "separate lockfile" approach on OSs that lack an atomic
    rename-over-existing-file.

    To save re-inventing the wheel, see the module IO::AtomicFile on CPAN.

    > Another question...


    Errr....

    > My perl script runs on a web server and when it is called, it does a
    > few quick things and terminates. When the perl script terminates,
    > will all files locked by the perl script be unlocked upon
    > termination (in the event that an error occured and it ended
    > prematurely - not that it would).


    [ Er, what was your question? I shall assume "It is true that ...?"]

    Under CGI yes, the above is true, because a CGI script runs as a
    separate process. When the process terminates all resources held by
    it are (or at least should be) freed by the OS.

    This is not necessarily the case under other mechanisms that may be
    used to connect your Perl script to the web server (mod_perl, FastCGI,
    whatever).

    Using a bare filehandle you can avoid this thus:

    local *FOO;
    open FOO, '<+', $filename or die "Can't open $filename: $!";

    This will close the file on exiting the current lexical scope, whether
    normally or abnormally.

    However, I suggest that people should always open files using
    filehandle references rather than bare filehandles except when
    backward compatability with old versions of Perl is needed. (And if
    you are using IO::AtomicFile you'd be using a reference anyhow).

    open my $foo, '<+', $filename or die "Can't open $filename: $!";

    This will close the file upon destruction of the last copy of the
    reference held in $foo. This will close the file upon termination so
    long as your program hasn't leaked any copies of the reference in
    $foo.

    Note that under mod_perl's Registry you can't declare $foo as a
    lexical variable at the file-scope an then use $foo within a
    subroutine.

    A workround for the latter is to use a package variable and local().

    open local our $foo, '<+', $filename or die "Can't open $filename: $!";

    > I think I was told that the web server is running perl 5.8???
    > This brings me to a final question.
    > Is there a function that can retrieve the version of Perl that is running?
    > This would be nice since the server is like 3 hours away (200 miles away!)


    $]

    --
    \\ ( )
    . _\\__[oo
    .__/ \\ /\@
    . l___\\
    # ll l\\
    ###LL LL\\
    Brian McCauley, Dec 1, 2003
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fuzzyman
    Replies:
    3
    Views:
    476
    Andrew MacIntyre
    Dec 5, 2003
  2. Robert Brewer
    Replies:
    0
    Views:
    478
    Robert Brewer
    Dec 5, 2003
  3. k3xji
    Replies:
    7
    Views:
    785
    Gabriel Genellina
    Dec 30, 2008
  4. John Carter
    Replies:
    16
    Views:
    225
    M. Edward (Ed) Borasky
    Aug 15, 2006
  5. J. Romano
    Replies:
    6
    Views:
    89
    Bob Walton
    Sep 4, 2004
Loading...

Share This Page