lock transactions: ensure that nested write transactions write

If a write transaction was nested inside a read transaction, it would not
write properly on release, e.g., in a sequence like this, inside our
`LockTransaction` class:

```
1  with spack.store.db.read_transaction():
2    with spack.store.db.write_transaction():
3      ...
4  with spack.store.db.read_transaction():
   ...
```

The WriteTransaction on line 2 had no way of knowing that its
`__exit__()` call was the last *write* in the nesting, and it would skip
calling its write function.

The `__exit__()` call of the `ReadTransaction` on line 1 wouldn't know
how to write, and the file would never be written.

The DB would be correct in memory, but the `ReadTransaction` on line 4
would re-read the whole DB assuming that other processes may have
modified it.  Since the DB was never written, we got stale data.

- [x] Make `Lock.release_write()` return `True` whenever we release the
      *last write* in a nest.
This commit is contained in:
Todd Gamblin
2019-12-21 16:29:53 -08:00
parent eb8fc4f3be
commit bb517fdb84
2 changed files with 64 additions and 1 deletions

View File

@@ -351,7 +351,13 @@ def release_write(self, release_fn=None):
else:
self._writes -= 1
return False
# when the last *write* is released, we call release_fn here
# instead of immediately before releasing the lock.
if self._writes == 0:
return release_fn() if release_fn is not None else True
else:
return False
def _debug(self, *args):
tty.debug(*args)