Skip to content

pinned

pinned #

Pinned — one process's hold on a sealed object; eviction never takes a held object.

One rule: the index changes only on an explicit call. Pinned() takes the hold and release() (or leaving the with block) lets it go; nothing runs from a finalizer. A pin dropped unreleased is noted on its scratch and let go at the next explicit call — another pin taken or released, or an eviction — and a process that dies holding pins is reclaimed by reconcile through its liveness lock.

Pinned #

A hold on one sealed object; the object stays until every hold is gone.

Source code in capturegraph-lib/capturegraph/recipes/scratch/store/pinned.py
class Pinned:
    """A hold on one sealed object; the object stays until every hold is gone."""

    __slots__ = ("__weakref__", "_finalizer", "_scratch", "hash", "path")

    def __init__(self, scratch: Scratch, hash: ContentHash) -> None:
        """Take one more hold on ``hash`` for this scratch's owner."""
        self.hash = hash
        self.path = scratch.object_dir(hash)
        self._scratch = scratch
        with scratch.database.transaction() as db:
            release_leaked(scratch, db)
            pins.acquire(db, hash, scratch.liveness.pid, scratch.liveness.boot)
        self._finalizer = weakref.finalize(self, scratch.leaked_pins.append, hash)
        self._finalizer.atexit = False

    def release(self) -> None:
        """Let go of the hold; a second call does nothing."""
        if not self._finalizer.detach() or self._scratch.closed:
            return
        with self._scratch.database.transaction() as db:
            pins.release(db, self.hash, self._scratch.liveness.boot)
            release_leaked(self._scratch, db)

    def __enter__(self) -> Pinned:
        """Hold the object for the block."""
        return self

    def __exit__(self, *_: object) -> None:
        """Release the hold."""
        self.release()

    def __repr__(self) -> str:
        """``Pinned(<hex>)``."""
        return f"Pinned({self.hash.hex})"

__enter__() #

Hold the object for the block.

Source code in capturegraph-lib/capturegraph/recipes/scratch/store/pinned.py
def __enter__(self) -> Pinned:
    """Hold the object for the block."""
    return self

__exit__(*_) #

Release the hold.

Source code in capturegraph-lib/capturegraph/recipes/scratch/store/pinned.py
def __exit__(self, *_: object) -> None:
    """Release the hold."""
    self.release()

__init__(scratch, hash) #

Take one more hold on hash for this scratch's owner.

Source code in capturegraph-lib/capturegraph/recipes/scratch/store/pinned.py
def __init__(self, scratch: Scratch, hash: ContentHash) -> None:
    """Take one more hold on ``hash`` for this scratch's owner."""
    self.hash = hash
    self.path = scratch.object_dir(hash)
    self._scratch = scratch
    with scratch.database.transaction() as db:
        release_leaked(scratch, db)
        pins.acquire(db, hash, scratch.liveness.pid, scratch.liveness.boot)
    self._finalizer = weakref.finalize(self, scratch.leaked_pins.append, hash)
    self._finalizer.atexit = False

__repr__() #

Pinned(<hex>).

Source code in capturegraph-lib/capturegraph/recipes/scratch/store/pinned.py
def __repr__(self) -> str:
    """``Pinned(<hex>)``."""
    return f"Pinned({self.hash.hex})"

release() #

Let go of the hold; a second call does nothing.

Source code in capturegraph-lib/capturegraph/recipes/scratch/store/pinned.py
def release(self) -> None:
    """Let go of the hold; a second call does nothing."""
    if not self._finalizer.detach() or self._scratch.closed:
        return
    with self._scratch.database.transaction() as db:
        pins.release(db, self.hash, self._scratch.liveness.boot)
        release_leaked(self._scratch, db)

release_leaked(scratch, db) #

Let go of every hold dropped unreleased since the last explicit call.

Source code in capturegraph-lib/capturegraph/recipes/scratch/store/pinned.py
def release_leaked(scratch: Scratch, db: sqlite3.Connection) -> None:
    """Let go of every hold dropped unreleased since the last explicit call."""
    leaked = scratch.leaked_pins
    while leaked:
        pins.release(db, leaked.popleft(), scratch.liveness.boot)