synology_apm_repo.sdk.storage.sqlite_source module¶
peel() + SqliteSource — unify the six envelope->SQLite paths
this project has:
source |
envelope chain |
|---|---|
repository |
raw |
|
aHlT? -> raw |
|
aHlT? -> zstd |
|
raw |
embedded |
raw |
service-level DB (saas_obj slice) |
zstd |
Only two envelope kinds exist (aHlT AES-CTR, then optionally a
standard ZSTD frame) and each is auto-detected by its own magic bytes, so
one small function handles every source in the table above — callers
never need to know in advance which of the six they have.
- synology_apm_repo.sdk.storage.sqlite_source.is_zstd_frame(head)¶
Whether
headopens with a standard ZSTD frame’s magic number — only the first 4 bytes are ever inspected, soheadneed not be the full payload. The exact checkpeeluses internally to decide whether to attempt decompression at all; exposed here so a caller that only wants to know whether something is zstd-framed before deciding how much to even read (e.g.units/saas/services.py’sinspect_object, choosing between a small head read and a full one) doesn’t need its own copy of the Codec Layer’s magic constant — seeARCHITECTURE.md’s “Cross-cutting shared mechanisms” on why drifting frompeel()’s own convention is treated as a real bug, not a style nit.
- class synology_apm_repo.sdk.storage.sqlite_source.Envelope(value)¶
Bases:
EnumWhich wrapper(s)
peelstripped, outermost first — purely informational (diagnostics/--verbose), callers never need to branch on it themselves.- AHLT = 'aHlT'¶
- ZSTD = 'zstd'¶
- synology_apm_repo.sdk.storage.sqlite_source.peel(data, *, vault_key=None, max_zstd_output_size=None)¶
Strip whichever envelope(s)
dataactually has, auto-detected by magic, returning(payload, envelopes_stripped).Raises
KeyRequiredErrorif the data isaHlT-enveloped but novault_keywas given. Never raises for the zstd step failing to apply — a payload simply isn’t zstd-framed if its first 4 bytes don’t match, a perfectly valid outcome (e.g. a plaindb/<name>file).max_zstd_output_size, forwarded todecompress_zstd_stream, bounds how much a genuinely zstd-matching frame may decompress to before raising — for callers peeling content of an unconfirmed type; omit it (default) for a source already known to be a trusted db snapshot.
- class synology_apm_repo.sdk.storage.sqlite_source.SqliteSource¶
Bases:
objectMaterialize raw SQLite bytes to a private temp file and open a connection to it — the common tail end of all six paths in this module’s docstring, once
peelhas produced plain SQLite bytes.Constructed via
await SqliteSource.from_bytes(...)/await SqliteSource.from_raw_store(...), async classmethod factories — seeTable.create.Async-context-manager friendly (
async with); also safe to justawaitclosedirectly once done. The temp file is created with a random name in the platform temp dir and unlinked on close — never touches the source repository (read-only invariant). The connection onto that temp file is deliberately writable; seefrom_bytes.- connection: Connection¶
- async classmethod from_bytes(data)¶
Materialize plain (post-
peel) SQLitedatato a private temp file and open a writable connection to it.Writable because the file is this instance’s own scratch copy, unlinked again by
close()— the store’s bytes are already behind us by the timedataexists, so the read-only invariant is upheld by what this never opens, not by the mode of this connection. It is also what letsapply_index_hintbuild a real index here instead of leaving every hinted query a full table scan.
- async classmethod from_raw_store(store, path)¶
Read and open
pathfromstore, for a caller that already knowspathis never enveloped (db/<name>,saas/*/db/saas_{version,snapshot}). Delegates toopen_sqlite, which materializespathitself and also handles a real non-empty-walsidecar.
- async classmethod from_enveloped_store(store, path, *, vault_key)¶
Read,
peel(), and openpathfromstore— for a source that may beaHlT-enveloped (copy_meta_file/*/target.db, FORMAT-SPEC.md: copy_meta_file-layout) and may have a real-wal/-shmsidecar, each peeled independently.
- async close()¶
Safe to call more than once — a second call is a no-op rather than raising
FileNotFoundErroron the already-unlinked temp file. A caller that closes a provider itself, ahead of the session-wide cleanup that would otherwise close it again at session end, must not crash that later, redundant close.