synology_apm_repo.sdk.units.device module¶
DeviceProvider: VM/PC/PS workloads via copy_meta_file.
The dedup engine’s own smallest recognized unit for these workload types
is still a whole disk/volume image (FORMAT-SPEC.md: copy_meta_file-layout) — this
provider’s disk-image leaves are exactly that, unchanged, and every
existing ref pointing at one keeps working identically. Every dedup
disk-image object also gets one additional, purely-additive sibling node —
“<name> (filesystem)” — built by units.content.disk_fs
(Dissect-framework-based) via units.device_disk_fs, that parses the
guest OS’s own filesystem
(NTFS/FAT/exFAT/ext2-4/XFS/Btrfs/APFS) inside that same disk image and
offers individual guest files as real, browsable/exportable
RestorableUnits. When Dissect can’t recognize any filesystem on a given
disk (encrypted, unsupported, or genuinely not a filesystem-bearing
image), that sibling node is simply absent or shows one diagnostic leaf
explaining why — the whole-image node is completely unaffected either
way.
Two distinct paths, dispatched directly on ``Version.target_type``
("VM" vs {"PC", "PS"}), never by probing which files exist — a
version’s target_type is already known the moment a Version is
constructed (db/copy_target_version.target_type, see catalog/version.py):
VM/FS:
target.db→ itsversion_tablerow →device_table(one row per disk device) →object_table(one row per disk image, joined onconfig_device_id). Handled directly in this module.PC/PS: the landing directory has no
target.db, onlysnapshot_info.json(FORMAT-SPEC.md: copy_meta_file-layout). The disk list instead comes from the destination repository’s owndb/copy_target_file(version_id→fid) joined withdb/file_meta(fid→path), looked up indb/file_mapthrough the same bridge the VM path uses — the same production code path populates both tables for VM and PC/PS alike. Handled bydevice_pcps.PcpsDiskTree, a collaboratorDeviceProviderdelegates to because one physical PC/PS disk can land as several independently-registered fragment objects, not one, andPcpsDiskTreeowns both the grouping rule and reassembling a group’s fragments into one disk.
Trap: a PC/PS landing directory exists for every normally-landed
version too, just without target.db — so “does copy_meta_file/<dir>
exist” can’t distinguish VM from PC/PS. target_type is the only
reliable dispatch signal.
- class synology_apm_repo.sdk.units.device.DeviceProvider(repo, version)¶
Bases:
objectUnitProviderfor one VM/PC/PS workload version.Build one with
create, neverDeviceProvider(...)directly — kept as the documented construction path even though it does no I/O (_is_pcpsis a pure function ofversion.target_type, decided once and cached rather than re-derived on every access), sorootstays synchronous.- async classmethod create(repo, version)¶
- property repo: DedupRepo¶
Exposed for
PcpsDiskTree/DiskFsSibling, the two collaborators this class delegates to.
- property disk_fs: DiskFsSibling¶
The disk-fs sibling collaborator — exposed so
PcpsDiskTreecan build a PC/PS disk’s own “(filesystem)” sibling node the same way this class’s own_object_nodesdoes for a VM disk.
- extra_ref(*extra)¶
Append to this provider’s own version ref rather than nesting
str(self._version_ref())as a newrepo_path— the latter bakes a literal#into the middle of the ref string, whichNodeRef.parse()(splitting on the first#only) then silently swallows into theversion_uidsegment on round-trip. Every other provider uses this same flat form viaNodeRef.canonical(..., extra=...). Public — also used byPcpsDiskTree.
- async close()¶
Release the sqlite connection(s) this provider opened.
Not merely for tidiness: an
aiosqliteconnection owns a background worker thread created withoutdaemon=True, so a provider abandoned without closing keeps the interpreter alive forever inthreading._shutdown.Repository.close()calls this for every provider it handed out, so ordinary callers never have to.
- root()¶
Pure construction, no I/O —
_is_pcpswas already resolved in__init__. Carries nodegraded/caveat attrs: whether this version’s objects actually resolve is only knowable by queryingcopy_target_file/file_meta/file_map, whichPcpsDiskTree.object_nodesdoes lazily, per call, not here.
- async children(node, offset=0, limit=None)¶
- async unit(node)¶