synology_apm_repo.sdk.units.saas.objectdb module¶
Embedded ObjectDB: object_id -> (offset, length) inside a
saas_obj. Unlike every other SQLite this project opens, an
ObjectDB isn’t addressed by a file_map path of its own — it’s a
tiny SQLite file embedded directly in the stream’s dedup content.
Located exclusively via an ``object_db_id`` string
("<streamUuid>_<offset>_<length>") — a direct DedupFile.view(offset,
length), no scanning of any kind. That string’s original source is the
connector package’s own SnapshotDB
(/<volume>/@ActiveBackup-GSuite/db/snapshot.sqlite and the M365
equivalent), which lives outside @ActiveProtectVault/
@ActiveProtectData and is never exported with a vault — but the
connector also copies it into the vault’s own object-name index, at
backup-completion time, as part of copy_target_version’s
additional_meta (see object_name_index.py). That copy is how every
application-layer provider — including RawObjectProvider — gets
this string automatically, offline, with no scanning at all; a caller
supplying one by hand (the CLI’s --object-db-id escape hatch) is
the manual exception, not the normal path.
- synology_apm_repo.sdk.units.saas.objectdb.parse_object_db_id(object_db_id)¶
Parse an
object_db_idstring ("<streamUuid>_<offset>_<length>") into(stream_uuid, offset, length)— the manual escape hatch for a caller that already knows the exact location and wants to hand it in directly rather than going through the object-name index.- Raises:
NotFoundError –
object_db_idisn’t shaped like<text>_<int>_<int>— the same category used elsewhere for an unresolvable location.
- synology_apm_repo.sdk.units.saas.objectdb.name_object_id_pairs(items)¶
Filters
itemsdown to the(name, object_id)pairs it actually holds, silently dropping anything that doesn’t match —itemsis expected to be a JSON array of{"name": str, "object_id": str}objects, the shape an object-name index’s owndb_objectsarray uses (object_name_index.pyandservices.py’s own INDEX-object sniffing both need this identical filter). Returns[]outright whenitemsisn’t even a list.
- class synology_apm_repo.sdk.units.saas.objectdb.ObjectDb¶
Bases:
objectobject_id -> (offset, length)lookup backed by one embedded ObjectDB slice, materialized viaSqliteSource. The envelope chain here is alwaysraw—peelis still run for uniformity, but is a no-op passthrough on real data.- async classmethod from_bytes(data)¶
Materializing the slice as SQLite and introspecting
object_tableare both I/O, so construction is an async classmethod factory rather than__init__.
- async classmethod load(dedup_file, offset, length)¶
- async close()¶
- async get(object_id)¶
- async object_map()¶
The full
object_id -> (offset, length)mapping.
- async synology_apm_repo.sdk.units.saas.objectdb.read_object(object_db, dedup_file, object_id, *, expected_size=None)¶
Read one object’s bytes eagerly via
object_db’sobject_id -> (offset, length)lookup — the shared shape behind every “read one already-located object, then parse/transform it” call site (calendar.py,contact.py,site.py’s META lookup,mail.py’s fragment/META reads). Deliberately eager (dedup_file.read(), not.view()): every one of those callers needs the bytes materialized in-process to parse JSON or decompress, unlikedrive.py/site.py’s content branch/raw_object.py, which hand back the final, unmodified content as a lazydedup_file.view()instead — those call sites must NOT be routed through this function, since that would force an eager read of what’s meant to stay a lazy, possibly-large stream.expected_size, when given, raisesDataCorruptErrorif the read doesn’t match it — the one extra check some callers (e.g. a mail fragment’s own META-declared size) need that a plain metadata read doesn’t; omit it (the default) to skip the check entirely.