4

I have a sort of checkpoint file which I wish to modify sometimes by various python programs. I load the file, try to lock it using portalocker, change it, than unlock and close it.

However, portalocker does not work in the simplest case. I created a simple file:

$echo "this is something here" >> test
$python
Python 3.5.2 (default, Jul  5 2016, 12:43:10) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import portalocker
>>> f = open("test",'w')
>>> portalocker.lock(f, portalocker.LOCK_EX)

Meanwhile I can still open it in another terminal:

$python
Python 3.5.2 (default, Jul  5 2016, 12:43:10) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> fl = open("test",'w')
>>> fl.write("I can still overwrite this\n")
>>> fl.close()

Then I close the first one, and check the file:

>>> portalocker.unlock(f)
>>> f.close()
>>> 
$ cat test
I can still overwrite this

What am I doing wrong?

Berta Dénes
  • 93
  • 3
  • 11
  • Can't repeat this on Windows with just released 0.6.0 - it fails on first `fl.close()` though, not on `fl.write()`. I propose you to open an issue here - https://github.com/WoLpH/portalocker/issues – anatoly techtonik Sep 05 '16 at 18:04
  • I think you should call portalocker.lock in the second terminal as well. This will then fail, telling you that the files is locked. – Konstantin Schubert Jul 22 '18 at 09:52

1 Answers1

9

NOTE: Since Linux 5.15 the mandatory locking feature has been removed from the kernel. Only advisory locks remain.

The problem is that, by default, Linux uses advisory locks. To enable mandatory locking (available up to Linux 5.15), which you are referring to, the filesytem needs to be mounted with the mand option. The advisory locking system actually has several advantages but can be confusing if you're not expecting it.

To make sure your code works properly in both cases I would suggest encapsulating both of the open calls with the locker.

For example, try this in 2 separate Python instances:

import portalocker

with portalocker.Lock('test') as fh:
    fh.write('first instance')
    print('waiting for your input')
    input()

Now from a second instance:

import portalocker

with portalocker.Lock('test') as fh:
    fh.write('second instance')

Ps: I'm the maintainer of the portalocker package

Wolph
  • 78,177
  • 11
  • 137
  • 148
  • Apparently I still don't get the functioning of this package clearly. I put your suggestion into a try/except loop, which seems to be working on the first go. On the other hand, I cannot really get rid of the lock. I tried to call release() method of the lock object I created, but the file I locked remain empty. – Berta Dénes Sep 12 '16 at 14:54
  • The library only handles locking, not reads or writes so if you write to the file it should write as expected. – Wolph Sep 14 '16 at 16:10
  • This example seems out of date, truncate doesn't seem to work (I guess a change in 1.0?), also timeout doesn't seem to have any effect. Using this example I get an exception immediately even though I set the timeout in terminal 2 to 10 – David Parks Jan 13 '17 at 23:19
  • 1
    @DavidParks: you're right, the `truncate` parameter has been removed in 1.0. As for the timeout, it does function but only when `fail_when_locked` is set to `False`. I've just pushed a new release that changes that behaviour, it's a bit clearer that way. – Wolph Jan 14 '17 at 03:12
  • `mount -o mand` does not exist anymore; also the linked stackoverflow page does not exist anymore as well – am70 Aug 17 '23 at 14:30
  • 1
    @am70 The stackoverflow page has been hidden because it's not really a programming question it seems. It does still exist but I suppose most people cannot see it anymore so I'll remove the link :) With regards to mandatory locking, you're right, since Linux 5.15 that has been removed (due to unfixable bugs) so our only remaining option is advisory locks unfortunately :( – Wolph Aug 25 '23 at 13:01