tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

bootstrap_retention_lock.py (1065B)


      1 """Cooperative scratch-root exclusion for generations and checkpoint cleanup.
      2 External users must still pin their stores and stop uncoordinated jobs.
      3 """
      4 import fcntl
      5 from pathlib import Path
      6 
      7 
      8 def scratch_root(path):
      9     path = Path(path).absolute()
     10     return next((p for p in (path, *path.parents) if p.name == '.bootstrap-run'), None)
     11 
     12 
     13 def acquire(root, exclusive=False):
     14     root = Path(root)
     15     root.mkdir(parents=True, exist_ok=True)
     16     path = root / '.retention.lock'
     17     if path.is_symlink():
     18         raise ValueError('symlink retention lock')
     19     handle = path.open('a')
     20     try:
     21         fcntl.flock(handle, (fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH) | fcntl.LOCK_NB)
     22     except BlockingIOError:
     23         handle.close()
     24         raise ValueError('scratch root is busy (generation or retention cleanup)')
     25     return handle
     26 
     27 
     28 def protect_generations(paths):
     29     # Keep the returned handles alive until the generation exits.
     30     roots = sorted({r for p in paths if p is not None for r in [scratch_root(p)] if r})
     31     return [acquire(r) for r in roots]