SealSkin

persistence

Atomic YAML persistence with per-file locks and change watching.

SealSkin keeps its configuration in hand-editable YAML files. This module is the single place that reads and writes them so every writer gets:

  • atomic replacement (temporary file in the same directory + os.replace),
  • one Lock per path so concurrent handlers never interleave,
  • a content hash of the last write so the file watcher can tell our own writes apart from edits made by an administrator.

A path under one of store.MOUNTS names an object the nodes of a cluster share. While the store is this node's own files that changes nothing; with a remote store those reads and writes go to it instead, each write conditional on the object being as this node last read it, so two nodes never overwrite each other unseen (store.Conflict). watch_store then stands in for the file watcher.

attributelogger
= logging.getLogger(__name__)
attributeReloadCallback
= Callable[[str], Awaitable[None]]
funclock_for(path) -> asyncio.Lock

Return the lock guarding path, creating it on first use.

parampathstr

File path (normalised with abspath).

Returns

asyncio.Lock

The Lock shared by every writer of that file.

funccontent_hash(data) -> str

Return the SHA-256 hex digest of data.

paramdatabytes

Returns

str
func_shared_key(path) -> str | None

Return the key of path in a remote store, or None for a file read and written in place.

parampathstr

Returns

str | None
funcread_bytes(path) -> bytes | None

Return the content of a file or shared object, or None when it does not exist.

parampathstr

Returns

bytes | None
funcwrite_bytes(path, data) -> None

Atomically write a file, or a shared object as this node last read it.

parampathstr
paramdatabytes

Returns

None
funcremove(path) -> None

Delete a file or shared object; a missing one is not an error.

parampathstr

Returns

None
funcexists(path) -> bool

Whether a file or shared object exists.

parampathstr

Returns

bool
funclist_names(directory) -> list[str]

Return the names of the files or shared objects directly inside directory, sorted.

paramdirectorystr

Returns

list[str]
funcread_yaml(path, default=None) -> Any

Load a YAML file.

parampathstr

File to read.

paramdefaultAny
= None

Value returned when the file does not exist or is empty.

Returns

typing.Any

The parsed document, or default.

funcdump_yaml(data) -> str

Serialise data the way every SealSkin file is written.

paramdataAny

Any YAML-serialisable structure.

Returns

str

YAML text with keys in insertion order.

func_write_file(path, encoded) -> None

Replace path with encoded through a temporary file in its directory.

parampathstr
paramencodedbytes

Returns

None
funcwrite_yaml_sync(path, data) -> None

Atomically write data to path as YAML.

The document is written to a temporary file in the target directory and moved into place with replace, so readers never observe a partially written file.

parampathstr

Destination file.

paramdataAny

YAML-serialisable structure.

Returns

None
funcwrite_yaml(path, data) -> None

Atomically write data to path under the file's lock.

parampathstr

Destination file.

paramdataAny

YAML-serialisable structure.

Returns

None
funcwas_written_by_us(path) -> bool

Tell whether the current contents of path match our last write.

parampathstr

File to check.

Returns

bool

True when the on-disk content hash equals the hash recorded by

funcwatch_paths(targets, stop_event, debounce_ms=500) -> None

Watch files and directories and call a callback when they change.

paramtargetsdict[str, ReloadCallback]

Mapping of path (file or directory) to the coroutine function invoked with the changed path. Directory targets fire for any file inside them.

paramstop_eventasyncio.Event

Set it to end the watch loop.

paramdebounce_msint
= 500

Quiet period before a batch of changes is reported.

Returns

None
funcwatch_store(targets, stop_event, interval=15.0, wake=None) -> None

Poll a remote store and call a callback when another node changed its objects.

paramtargetsdict[str, ReloadCallback]

The same mapping watch_paths takes; each path is matched by its key in the store.

paramstop_eventasyncio.Event

Set it to end the loop.

paramintervalfloat
= 15.0

Seconds between two polls.

paramwakeasyncio.Event | None
= None

Set it to poll at once, as when a peer announces a change.

Returns

None