synology_apm_repo.sdk.storage.generations module

S3/Azure db/<name>.<N> generation selection (FORMAT-SPEC.md: generation-selection). The single place this rule lives; dircache.py, seqid.py, s3.py and dedup/repository.py’s db() all point here rather than restating it.

Why the naive “largest ``.<N>`` suffix” rule (resolve_seq_file) is not enough here, unlike every other per-generation file this SDK reads: a db/<name> generation can be written to S3/Azure before the transaction that references it is actually committed, so the largest suffix present can be a not-yet-committed or long-superseded generation. The correct answer needs the transaction log:

  1. ``latest_txn`` (latest_transaction_id): the largest repo_transactions/repo_transaction.<N> filename, opened and parsed — the answer is that file’s embedded transaction_id, never the filename’s own <N> (the two are not the same number).

  2. ``file_map``/``repo_info`` (anything not in SUPPLEMENTAL_TABLES): among db/<name>.<N>’s suffixes, the largest one strictly less than latest_txn — a generation written at or after the latest committed transaction is exactly the “written but not yet committed” case above.

  3. The 9 supplemental tables (SUPPLEMENTAL_TABLES) use an independent, simpler rule: the largest suffix that also has a matching suppl_transaction_ids/<N> marker file — a numbering completely unrelated to repo_transactions/’s own.

A logical name with no .<N> variant at all falls back to the bare, unsuffixed name — the same file the naive rule would have picked anyway.

synology_apm_repo.sdk.storage.generations.SUPPLEMENTAL_TABLES = frozenset({'agent_connection', 'connection_config', 'copy_file', 'copy_source_version', 'copy_target_file', 'copy_target_version', 'copy_target_version_meta', 'file_meta', 'workload_config'})

This project’s supplemental-table set — resolved by the suppl_transaction_ids/ marker rule, not the transaction-log rule. See FORMAT-SPEC.md: generation-selection. copy_target_file shares its physical file with copy_target_version (same on-disk name) but is listed here anyway for completeness — see PHYSICAL_NAME_ALIASES for where that sharing is actually enforced, not just documented.

synology_apm_repo.sdk.storage.generations.PHYSICAL_NAME_ALIASES: dict[str, str] = {'copy_target_file': 'copy_target_version'}

Logical db/<name> names that are not their own on-disk object at all — copy_target_file has no copy_target_file[.N] object anywhere on a real repository; the copy_target_file table lives inside whichever generation copy_target_version[.N] resolves to (same physical sqlite file — both tables are written through one connection on the write side). Without this alias, DedupRepo.db("copy_target_file") would search db/ for an object literally named that and raise NotFoundError — there is none — starving the PC/PS browse path (PcpsDiskTree.object_nodes()) of its whole object list. Consulted by DedupRepo.db before any generation resolution happens, so it applies uniformly on both VAULT and OBJECT_STORE layouts — this is a fact about how the two tables are physically stored, not an object-store-specific generation-selection quirk.

async synology_apm_repo.sdk.storage.generations.latest_transaction_id(store, transactions_dir)

The latest committed transaction id, per FORMAT-SPEC.md: generation-selection.

async synology_apm_repo.sdk.storage.generations.resolve_generation(store, db_dir, name, *, transactions_dir, suppl_dir)

The correct db/<name>[.<N>] logical path for name on an OBJECT_STORE layout: the largest .<N> strictly less than the latest committed transaction for most tables, or the largest .<N> with a matching suppl_transaction_ids marker for the 9 supplemental tables (FORMAT-SPEC.md: generation-selection). db_dir/transactions_dir/ suppl_dir are already joined with layout.repo_root by the caller.

Raises NotFoundError if name has .<N> variants present but none of them is actually valid per the rule that applies to it (a genuinely inconsistent/partial repository copy, not something this function should silently paper over).