mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[GH-ISSUE #363] [Design Proposal] Snapshot data migration from OSS/POSIX to SQL #91
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#91
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @guozy18 on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/kvcache-ai/AgentENV/issues/363
Affected component
Snapshot / template builder
Problem statement
Part of the parent proposal, using the data model, sandbox hold contract, the online GC rules, and upgrade compatibility.
Snapshot metadata and runtime descriptions are split across records, alias files, and a separate runtime manifest. Copying only the record loses facts needed to resume the same VM or protect its complete dependencies. The transition must also preserve publication, deletion, builds, and existing consumers: a static copy and configuration switch cannot prevent a late write from being lost or an old file from reviving a snapshot already deleted in SQL.
Use case
An existing OSS or POSIX repository is moving to SQL while users continue creating, reading, publishing, pausing, and restoring sandboxes. Metadata can move gradually while long-lived consumers keep their VM state and layer bytes at existing locations. S denotes a public snapshot, U an existing layer UUID brought under the unified identity contract, and H a shared usage hold. Examples use shortened identifiers and digests, not an executable dump; no second layer identity is introduced.
Current behavior and workarounds
A Distributed snapshot combines business metadata and layer references in a record, backend and virtual-size information in a runtime manifest, and binary artifacts. Local records also identify the publishing node; complete private inputs stay with that process. Record/alias queries do not establish a database-visible hold. Deletion removes metadata and performs backend cleanup, while shared-layer reclamation is separate.
Desired behavior
Proposed approach
1. Before and after: repository layout
OSS directories below are key prefixes. Other bucket contents and registry-internal layouts are outside these trees.
POSIX escapes colons and slashes in a digest to underscores; OSS does not use this filename transformation or the POSIX commit marker. Import the actual path, not a reconstructed path from another backend.
These are responsibility and layout sketches, not a frozen DDL or manifest pathname convention. The complete immutable manifest remains in the backend; SQL becomes authoritative for publication, names, dependency heads and holds. A successful manifest upload alone does not publish S. The verified manifest reference, newly registered layers and heads commit together.
Old record, alias, runtime-manifest, lock, and commit files remain during verification and compatibility cleanup. Removing a manifest never authorizes deleting its whole artifact directory. New layer identity and physical deletion/reuse rules must be settled under #361/#364 before reclamation is enabled; retaining digest-based paths is not itself proof that a late DELETE cannot affect a later publication.
Generated OverlayBD image configs, Local private files, paused artifacts, writable uppers, and byte/P2P caches remain node-owned. Registry manifests/configs/blobs remain registry artifacts. AENV-owned retention roots, VM state and startup artifacts retain explicit protection under their respective ownership rules; replacing layer mappings does not remove those obligations.
2. Map every source of metadata
New lifecycle fields are initialized only for verified, previously absent target rows. Re-import must not reset retirement, released holds or deletion states, overwrite a published manifest reference, or reinstall already-released heads.
A non-null file UUID is not sufficient evidence of the new identity contract. Classify legacy layers with missing/nil UUIDs, duplicate UUIDs, conflicting content descriptors, or absent/inconsistent predecessors. Validated layers may retain their UUIDs and bytes. Others require an explicit compatibility or conversion outcome before entering the authoritative graph; do not guess a predecessor, silently allocate an unrelated database-only layer identity, or force conflicting rows together.
If normalization requires a new artifact, create a new copy and immutable manifest, and account for any successor layers whose embedded parent changes. Never rewrite a file in place while it may be hard-linked, read by an existing VM, or served through P2P. Existing consumers keep their fixed old inputs and protection. The exact normalization and UUID-generation algorithm belongs to #361, not to the importer.
3. A concrete Distributed snapshot
Suppose a verified legacy S0, alias
python-base, uses rootfs[A, B], memory[M], and a read-only attached drive that also uses[A, B]. A and M have no predecessor; B names A as its predecessor. Their existing UUIDs satisfy the new contract.The importer combines the old record and runtime manifest into one immutable manifest, denoted
MF0. It preserves resources, runtime and startup contexts, commands, versions, source image configs, extension parameters, virtual sizes, drive IDs/mounts/subpaths, and exact layer/VM-state locators. In abbreviated form:MF0is an exact immutable backend reference, not a mutable filename that later publications overwrite. After preparing it outside the SQL transaction, the importer commits this logical state atomically:python-base, original created_at and business metadata, publication/type facts, manifest_ref=MF0, not retiredThe rootfs and attached drive share B as a head. Their separate roles and layer order remain in MF0; SQL does not duplicate the whole
[A, B]mapping for either role. A later snapshot[A, B, C]can reuse A/B and register C plus its head when the producer contract permits it.No active
snapshot_pinscan be inferred from these files. Real consumers acquire or adopt H. Absence of imported H is not evidence that GC is safe. A legacy digest reused under conflicting predecessors cannot be treated like this verified example merely because its bytes exist; it follows the identity-validation path above.4. Unpublished templates, Local files, and registry roots
An old template may default to Distributed while committed is null. Import it as non-runnable, without a published manifest reference or heads. Preserve requested resources, build status/error and timestamps rather than inventing completed content. Publication records actual resources and resolves the requested-resource state atomically. A resulting 4 GiB rootfs is 4096 MiB, not the original requested disk size 0.
A Local record may have owner_node_id=N1 and empty committed arrays even though its actual inputs depend on remote layers. Importing requires the original process's complete fixed inputs. Its manifest may describe relative private files and remote layers, but publishing that description does not grant another process ownership of the private files. Shared ancestors still need their verified heads and source protection; private files do not become independently reclaimable OSS artifacts.
A new process cannot recover public Local content from a node name or leftover directory. Preserve the original process for a verified handoff, or promote there before importing Distributed content. Retain the union of old/new protection needed by existing readers; do not assume the promoted inputs cover all earlier inputs. Without the original inputs, keep the snapshot unavailable or explicitly retire it.
For registry publications, preserve exact repository/manifest identities, subjects, provenance and retention responsibilities. Verify the fixed public tag before recording imageRef readiness. Do not rewrite registry bytes or create a digest merely to import metadata. External layers that depend on an AENV-created retention root must retain it; an unrelated source image does not become AENV-owned. The layer forest alone does not define registry or shared non-layer reclamation.
5. Keep operations available while importing
First create the schema and deploy compatible nodes that still serve the file catalog. Add capacity, stop assigning new work to old nodes, and keep their existing bindings and consumers until their responsibilities end. A compatible node's readiness checks both SQL and object storage.
The compatible Repository uses fixed modes Oss, Mixed and SqlOnly, records source H and dependencies from the OSS phase, and disables direct physical Delete/rollback bypasses. All metadata writers, tools and asynchronous callbacks must use the common entry point before Mixed starts.
For metadata modification/import, acquire sorted alias locks before sorted S locks and recheck names and mode. These migration locks precede Catalog transaction locks; do not hold a long SQL transaction around storage I/O.
Before an old metadata write, independently commit a durable, cross-process-visible intent. Order its completion confirmation against the Mixed switch in a control transaction:
Unknown old writes retain their S/alias marker. A dropped connection, released lock, or one successful HEAD/GET does not prove that a late write cannot arrive.
Foreground requests and the background tool share
ensure_imported(S): resolve pending old writes, accept an existing SQL row including a tombstone, otherwise verify the complete legacy inputs, prepare their immutable manifest, and atomically register its reference, validated layers and required heads/protection. Do not overwrite an existing SQL result.Alias claims check all SQL reservations, then untouched old alias files and their target records under the same arbitration. SQL absence alone does not make a legacy name free.
List precedence includes SQL tombstones and rows excluded by the user's filter, so an old live record cannot reappear. Apply one
(created_at DESC, snapshot_id ASC)order and cursor after merging; never concatenate independently paged backend results. Mixed retains scanning costs without promising a fixed snapshot across pages.The background tool checkpoints batches and retries through the same helper. Resolve pre-switch submissions, scan the resulting stable record/alias scope, and require an explicit outcome for every old record. Two unchanged listings alone do not prove completion.
6. Adopt existing consumers before enabling reclamation
Each compatible executor stops creating new OSS-only holds before auditing its acquiring, held, paused and background responsibilities. New cold preparation uses ordinary SQL Pin; existing consumers keep their fixed files and devices.
A migration-only
adopt_existing_hold(H,S,inputs)atomically registers the original active H, the verified heads of its fixed layer inputs and any other required protection. It can protect an already-retired S; if the source record was deleted, create a retired, unreleased identity without republishing it or claiming a historical alias.Adopt and Release follow the common H-to-S ordering and the layer/reference arbitration defined by #361/#364. Closed H never reopens. Adoption only adds necessary protection; it does not replace the current manifest_ref, reinstall protection after completed unlinking, or bypass a deleting/terminal layer state through ordinary import or adoption. Missing bytes, conflicting descriptors/UUIDs and incomplete provenance remain unresolved and conservatively retained for reconciliation; they are not evidence that import or consumer adoption is complete.
Include disconnected executors and direct tools in the audit. Completion means every legacy responsibility was returned or adopted, not merely that current online nodes reported success.
During Mixed/adoption, do not advance F or enable reference removal, payload compaction, identity pruning or physical GC. After full import and adoption, enter SqlOnly and close fallback/import/adopt; only then enable the applicable online cleanup. Long-lived paused consumers can remain protected without exiting.
Once S is retired, has no active H and has safely released its heads and other obligations, eligible payload/reference cleanup follows #364. Clearing manifest_ref or deleting a manifest is not permission to delete a whole artifact directory. A named S keeps its alias reservation; eligible unnamed S and Closed H may later be pruned under the historical-data rules. Active H does not expire. Layer terminal retention and physical-key reuse are separate decisions and must be settled before enabling that cleanup.
Compatibility and operational impact
Alternatives considered
A one-time export misses mutations; uncoordinated dual writes create conflicting authorities; a maintenance pause violates availability. Waiting for all old consumers avoids adoption but lets long-lived paused consumers indefinitely delay GC, so this proposal adopts their existing responsibility.
Non-goals
Do not move live VMs, mutate existing layer bytes in place, redesign external images or volumes, infer usage from cache directories, or implement a separate CDC platform. Any new normalized artifact must have an explicit identity and compatibility plan; this issue does not select the OCI UUID algorithm, layer tombstone policy, or a common volume schema. Do not treat successful row copying as proof that migration and recovery are complete.
Contribution
I can provide more design details
Pre-submission checklist