in reply to Frustration with changing lock type

Hmm, a quick test shows that I can quite happily downgrade a flock()-style lock on my Linux system without first releasing it. However perldoc -f flock shows a lot of O/S-specific (or rather, emulation-specific) caveats, and I imagine you're getting a different emulation under Win32.

One approach would be to append your process data to the file while you have the exclusive lock, then after unlocking and reacquiring a shared lock verify that yours is still the last line in the file. If it isn't, you must then unlock and go back to the beginning again.

With this approach you might also want to reduce the risk of runaway on a busy system by checking the last modified time and sleeping for a second or two before trying to acquire the exclusive lock if it has only just changed.

If you get the shared lock while your process is still the last named, you can then truncate the file back to containing just one line.

Hugo

Replies are listed 'Best First'.
Re: Re: Frustration with changing lock type
by demerphq (Chancellor) on Apr 14, 2004 at 12:37 UTC

    Thanks for the reply Hugo. I went with something like what you suggest. Added a test before we try to aquire the LOCK_EX to make sure the lockfile doesnt exist or is at least 3 seconds old, and double checking that the process data stays the same after the LOCK_UN and LOCK_SH. The append logic I didnt quite follow so I didnt go that way. Here is what I have:

    Yes its a bit wordy, id be interested to see a less clunky implementation if anyone feels inclined.

    Incidentally there is no need to wait to get the exclusive lock. Under normal situations this will be polling a table in a DB every 60 seconds or so, and then processing any records it finds there. So if the lock file is too young returning to try the next record is better.

    Cheers


    ---
    demerphq

      First they ignore you, then they laugh at you, then they fight you, then you win.
      -- Gandhi


      Hmm, I think you still have a race in the OnDestroy: if I understand flock() correctly, the lock is released as soon as you close the filehandle, so the unlink() happens after the lock has been released.

      If I remember right, Win32 doesn't let you unlink a file while anyone still has a handle open on it, so maybe it would be better instead to truncate the file to zero bytes on completion, which is something you can do with an open filehandle.

      Hugo

        Hmm, I think you still have a race in the OnDestroy: if I understand flock() correctly, the lock is released as soon as you close the filehandle, so the unlink() happens after the lock has been released.

        Hmm, I see what you mean. The thing is that the OnDestroy doesnt happen until after the record that this job is about is deleted from the DB. So once the deletion occurs the lockfile is more or less irrelevent as no other job can now get it. We requery the queue after every successful task, so I _think_ the race condition is covered. But maybe im wrong, and maybe there is even a better way to go about this.

        Actually the more i think about it the more I think I am wrong. Hmm.


        ---
        demerphq

          First they ignore you, then they laugh at you, then they fight you, then you win.
          -- Gandhi


        If I remember right, Win32 doesn't let you unlink a file while anyone still has a handle open on it

        No, that is just a type of sharing that you can specify. The C RTL defaults to opening files sharing both read and write access but not sharing rename/delete access.

        If you want to delete a file while you have it open in Perl, you can use Win32API::File to open the file and specify that you want to allow FILE_SHARE_DELETE.

        - tye