mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[GH-ISSUE #120] Advance memory snapshot epochs for linear incremental OverlayBD chains #42
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#42
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 @xeonliu on GitHub (Aug 4, 2026).
Original GitHub issue: https://github.com/kvcache-ai/AgentENV/issues/120
Affected component
Snapshot / template builder
Problem statement
AgentENV can capture a running sandbox without terminating it. The Firecracker
backend pauses the VM, creates snapshot artifacts, and then resumes the same
Firecracker process in place. However, the sandbox's launch configuration
continues to refer to the memory image from which that process originally
started.
This is compatible with the current
mincorebehavior because each capturecan include a broad resident-page set and remain a sibling over the original
launch parent. It is not sufficient for true per-checkpoint dirty-page
snapshots.
For example, suppose a VM starts from
S0:If the dirty epoch is reset after
S1, the newest layer forS2naturallycontains B, not A. If AgentENV still builds
S2overS0, the result isincomplete:
Simply enabling dirty tracking and clearing its bitmap after every capture can
therefore create snapshots that are missing memory changes. AgentENV needs an
explicit live memory parent, a transactional dirty epoch, and artifact
lifetime rules before it can provide deltas relative to the latest successful
capture.
Companion issue: #119
Use case
Agent and RL workloads frequently capture or fork the same running sandbox at
multiple decision points. A long-running VM may modify only a small page set
between checkpoints, while each checkpoint becomes a base for later rollback,
fork, template publication, or migration.
These workloads need a linear memory checkpoint chain in which each new
OverlayBD layer is relative to the immediately preceding successful local
capture. Without that chain, dirty tracking must either retain an ever-growing
write set relative to the original launch parent or risk producing an
incomplete snapshot.
Current behavior and workarounds
During capture,
snapshot_to_dirchooses inherited memory layers fromLaunchMode::Resumeand appends the newoverlaybd.commit. A non-terminalcapture_snapshotthen resumes the same process, but it does not advance thelaunch mode or another explicit current-memory-parent field to the newly
captured
mem_image.json.Current options are insufficient:
correct but later captures repeat every page written during the VM's
lifetime.
mincoreso captures contain a broad resident set. This avoids an epochdependency but is not a true write-based incremental mechanism.
snapshot. This establishes a new parent but adds avoidable lifecycle and
restore latency.
define which parent a new delta is relative to.
The direct dirty-range path also needs a clear transaction boundary. Dirty
state must not be discarded until AgentENV has sealed the OverlayBD layer,
atomically written its memory image config, and retained every referenced
parent artifact. Firecracker issue #4545 and PR #4580 document the same class
of failure for native Diff snapshots:
Desired behavior
memory parent to the captured memory image.
the original launch snapshot.
the new layer is sealed,
mem_image.jsonis durable, and inherited artifactsremain owned or pinned.
epoch remain active so retry cannot omit pages.
running sandbox still has a valid local parent chain and can be captured or
paused again.
publication all preserve the same layer ordering and ownership rules.
Proposed approach
Introduce explicit current memory lineage in
FirecrackerSandbox, separatefrom immutable launch provenance. Conceptually:
On capture:
process_vm_readv -> compact_to -> overlaybd.commitpath.mem_image.jsonfromcurrent_memory_parent + new layer.all referenced local artifacts.
current_memory_parentwith the candidate config.If any step before the local commit point fails, abort the candidate, preserve
the previous parent, and keep or merge the dirty set for retry.
The custom
/vm/dirty-memory-rangesAPI may need begin/read and commit/abortsemantics. If extending the direct API is not desirable, an initial
implementation could use Firecracker's native transactional Diff snapshot and
retain the intermediate
mem.binuntil OverlayBD conversion commits. Aconversion failure must not delete the only copy of a successfully dumped
epoch and then resume with cleared dirty state.
I would like maintainer feedback on:
independent sibling snapshots over the launch parent?
dirty-epoch commit point, or should repository publication participate?
FirecrackerSandbox, or berepresented by a separate lineage/lease object shared with snapshot
artifact ownership?
/vm/dirty-memory-rangesacceptable, or isthe native
mem.bintransaction preferred for the first implementation?Compatibility and operational impact
Introduce explicit current memory lineage in
FirecrackerSandbox, separatefrom immutable launch provenance. Conceptually:
On capture:
process_vm_readv -> compact_to -> overlaybd.commitpath.mem_image.jsonfromcurrent_memory_parent + new layer.all referenced local artifacts.
current_memory_parentwith the candidate config.If any step before the local commit point fails, abort the candidate, preserve
the previous parent, and keep or merge the dirty set for retry.
The custom
/vm/dirty-memory-rangesAPI may need begin/read and commit/abortsemantics. If extending the direct API is not desirable, an initial
implementation could use Firecracker's native transactional Diff snapshot and
retain the intermediate
mem.binuntil OverlayBD conversion commits. Aconversion failure must not delete the only copy of a successfully dumped
epoch and then resume with cleared dirty state.
I would like maintainer feedback on:
independent sibling snapshots over the launch parent?
dirty-epoch commit point, or should repository publication participate?
FirecrackerSandbox, or berepresented by a separate lineage/lease object shared with snapshot
artifact ownership?
/vm/dirty-memory-rangesacceptable, or isthe native
mem.bintransaction preferred for the first implementation?Compatibility and operational impact
API/config changes:
commit/abort operations.
by the companion issue.
Snapshot or storage format changes:
mem_image.jsonand committedmemory_layersremain orderedbottom-up using existing immutable OverlayBD layers.
remain important.
New host/runtime requirements:
opt-in mode from the companion issue.
running sandbox; memory/disk impact should be measured and bounded.
Upgrade and rollback considerations:
resume across a server restart.
reconstruct the corresponding parent chain.
are enabled; it must not silently reinterpret an already advanced epoch.
Alternatives considered
write set. Correct and simpler, but every later capture repeats all writes
since launch.
backing parent but adds restore latency and disrupts the non-terminal capture
workflow.
mincore: broad sparse captures can remain siblings, butread-only resident pages continue to inflate layers.
holds the VM paused across potentially slow remote I/O and couples local
correctness to repository availability.
harder to benchmark page tracking independently and mixes Firecracker page
selection with AgentENV lineage/artifact ownership.
Non-goals
mincoreand KVM dirty tracking; that belongs to thecompanion issue.
Contribution
I can implement it
Pre-submission checklist
@yingdi-shan commented on GitHub (Aug 4, 2026):
Thanks for raising this. The current behavior is intentional: non-terminal captures remain independent snapshots over the launch-time memory parent rather than advancing the running VM’s memory parent after every capture.
The main reason is storage reclamation. With many capture/resume cycles, workloads often write repeatedly to the same hot memory regions. A linear chain would preserve a new version of those pages in every immutable OverlayBD layer:
Although only the newest version is visible in the latest snapshot, the older versions cannot be reclaimed while descendants still reference those layers.
Linear layering is acceptable for disk snapshots because disk data generally changes much less than memory between captures. Memory has much higher write volume and churn, so repeated snapshots can quickly accumulate many obsolete copies of the same hot pages.
With the current sibling-snapshot model, each capture is independently restorable from its launch parent. When an older snapshot is no longer needed, its complete delta can be deleted without rewriting or invalidating newer snapshots.
The tradeoff is that each capture may rewrite a larger cumulative resident or dirty set, resulting in longer pause time and additional snapshot I/O. We currently prefer simpler ownership and predictable space reclamation over shorter incremental pauses with an ever-growing dependent layer chain.
This is still a valuable direction, but it requires garbage collection that periodically compacts multiple memory layers into a single layer so obsolete page versions can be reclaimed.