forkd 0.3.4__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {forkd-0.3.4 → forkd-0.5.2}/PKG-INFO +1 -1
- {forkd-0.3.4 → forkd-0.5.2}/forkd/__init__.py +9 -3
- {forkd-0.3.4 → forkd-0.5.2}/forkd/controller.py +64 -12
- {forkd-0.3.4 → forkd-0.5.2}/forkd.egg-info/PKG-INFO +1 -1
- {forkd-0.3.4 → forkd-0.5.2}/pyproject.toml +1 -1
- {forkd-0.3.4 → forkd-0.5.2}/README.md +0 -0
- {forkd-0.3.4 → forkd-0.5.2}/forkd/sandbox.py +0 -0
- {forkd-0.3.4 → forkd-0.5.2}/forkd.egg-info/SOURCES.txt +0 -0
- {forkd-0.3.4 → forkd-0.5.2}/forkd.egg-info/dependency_links.txt +0 -0
- {forkd-0.3.4 → forkd-0.5.2}/forkd.egg-info/top_level.txt +0 -0
- {forkd-0.3.4 → forkd-0.5.2}/setup.cfg +0 -0
|
@@ -11,8 +11,14 @@ Most agent runtimes use both: ``Controller`` to spawn / branch / kill,
|
|
|
11
11
|
``Sandbox`` to drive code execution inside one specific child.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
from .controller import Controller, ControllerError
|
|
14
|
+
from .controller import BranchMode, Controller, ControllerError
|
|
15
15
|
from .sandbox import CommandResult, Sandbox
|
|
16
16
|
|
|
17
|
-
__version__ = "0.
|
|
18
|
-
__all__ = [
|
|
17
|
+
__version__ = "0.5.1"
|
|
18
|
+
__all__ = [
|
|
19
|
+
"Sandbox",
|
|
20
|
+
"CommandResult",
|
|
21
|
+
"Controller",
|
|
22
|
+
"ControllerError",
|
|
23
|
+
"BranchMode",
|
|
24
|
+
]
|
|
@@ -36,7 +36,18 @@ import json
|
|
|
36
36
|
import os
|
|
37
37
|
import urllib.error
|
|
38
38
|
import urllib.request
|
|
39
|
-
from typing import Any, Optional
|
|
39
|
+
from typing import Any, Literal, Optional
|
|
40
|
+
|
|
41
|
+
BranchMode = Literal["full", "diff", "live"]
|
|
42
|
+
"""Canonical BRANCH mode selector (Phase 7.1+).
|
|
43
|
+
|
|
44
|
+
- ``"full"`` — copy entire guest RAM under pause (default for v0.x).
|
|
45
|
+
- ``"diff"`` — Firecracker Diff snapshot (v0.3+). Sub-second pause for
|
|
46
|
+
idle sources; replaces the legacy ``diff=True`` boolean.
|
|
47
|
+
- ``"live"`` — UFFD_WP-based live BRANCH (v0.4+). Source pause drops to
|
|
48
|
+
sub-50 ms; memory streams from the running parent. Requires the
|
|
49
|
+
source to have been spawned with ``live_fork=True``.
|
|
50
|
+
"""
|
|
40
51
|
|
|
41
52
|
|
|
42
53
|
class ControllerError(RuntimeError):
|
|
@@ -105,6 +116,8 @@ class Controller:
|
|
|
105
116
|
per_child_netns: bool = False,
|
|
106
117
|
memory_limit_mib: Optional[int] = None,
|
|
107
118
|
prewarm: bool = False,
|
|
119
|
+
live_fork: bool = False,
|
|
120
|
+
hugepages: bool = False,
|
|
108
121
|
) -> list[dict]:
|
|
109
122
|
"""``POST /v1/sandboxes`` — fork N children from a snapshot tag.
|
|
110
123
|
|
|
@@ -117,6 +130,21 @@ class Controller:
|
|
|
117
130
|
for steady-state BRANCH latency on the first user-visible
|
|
118
131
|
BRANCH (avoids the 2-9× cold-cache penalty documented in
|
|
119
132
|
``bench/pause-window/RESULTS-v0.2.md``).
|
|
133
|
+
live_fork:
|
|
134
|
+
v0.4+. Boot the sandbox with a memfd-backed RAM region so
|
|
135
|
+
later BRANCHes from it can use ``mode="live"`` (UFFD_WP).
|
|
136
|
+
Requires kernel 5.7+ and the vendored Firecracker fork —
|
|
137
|
+
see ``docs/VENDORED-FIRECRACKER.md``. No effect at spawn
|
|
138
|
+
time beyond the backend swap; cost shows up on the first
|
|
139
|
+
live BRANCH.
|
|
140
|
+
hugepages:
|
|
141
|
+
v0.4+. Back the memfd with 2 MiB hugepages
|
|
142
|
+
(``MFD_HUGETLB | MFD_HUGE_2MB``). Only meaningful with
|
|
143
|
+
``live_fork=True``. Reduces TLB pressure during spawn-many
|
|
144
|
+
and live BRANCH bulk-copy. Requires non-zero
|
|
145
|
+
``HugePages_Free`` in ``/proc/meminfo`` — ``forkd doctor``
|
|
146
|
+
checks availability. Falls back to normal 4 KiB pages with
|
|
147
|
+
a warning if the pool is exhausted.
|
|
120
148
|
|
|
121
149
|
Returns the list of SandboxInfo dicts (id, snapshot_tag, netns,
|
|
122
150
|
guest_addr, created_at_unix, pid, memory_limit_mib).
|
|
@@ -130,6 +158,10 @@ class Controller:
|
|
|
130
158
|
body["memory_limit_mib"] = memory_limit_mib
|
|
131
159
|
if prewarm:
|
|
132
160
|
body["prewarm"] = True
|
|
161
|
+
if live_fork:
|
|
162
|
+
body["live_fork"] = True
|
|
163
|
+
if hugepages:
|
|
164
|
+
body["hugepages"] = True
|
|
133
165
|
return self._request("POST", "/v1/sandboxes", body)
|
|
134
166
|
|
|
135
167
|
def list_sandboxes(self) -> list[dict]:
|
|
@@ -150,29 +182,40 @@ class Controller:
|
|
|
150
182
|
tag: Optional[str] = None,
|
|
151
183
|
diff: bool = False,
|
|
152
184
|
measure_diff: bool = False,
|
|
185
|
+
mode: Optional[BranchMode] = None,
|
|
186
|
+
wait: bool = True,
|
|
153
187
|
) -> dict:
|
|
154
188
|
"""``POST /v1/sandboxes/:id/branch`` — pause + snapshot + resume.
|
|
155
189
|
|
|
156
190
|
Parameters
|
|
157
191
|
----------
|
|
192
|
+
mode:
|
|
193
|
+
v0.4+ canonical selector. ``"full"``, ``"diff"``, or
|
|
194
|
+
``"live"``. When set, takes precedence over the legacy
|
|
195
|
+
``diff`` boolean — and passing both raises
|
|
196
|
+
:class:`ControllerError` (HTTP 400). Prefer this over
|
|
197
|
+
``diff=`` in new code. See :data:`BranchMode`.
|
|
158
198
|
diff:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
workloads; up to 143× on a 4 GiB sandbox on commodity
|
|
163
|
-
SSD — see ``bench/pause-window/RESULTS-v0.3.md``). Multi-
|
|
164
|
-
BRANCH on the same source is supported in v0.3.1+ via
|
|
165
|
-
the previous-output chain (``last_branch_memory_path``).
|
|
199
|
+
**Legacy.** Equivalent to ``mode="diff"``; kept so this SDK
|
|
200
|
+
can drive v0.3.x daemons that don't understand ``mode``.
|
|
201
|
+
Mutually exclusive with ``mode`` (server-side).
|
|
166
202
|
measure_diff:
|
|
167
203
|
v0.3+: measurement-only hook. Take a Diff snapshot inside
|
|
168
204
|
the existing Full pause to report what diff would have
|
|
169
205
|
cost, without changing semantics. Mutually exclusive with
|
|
170
206
|
``diff`` (daemon returns 400 if both are true).
|
|
207
|
+
wait:
|
|
208
|
+
v0.4+, only meaningful with ``mode="live"``. Default
|
|
209
|
+
``True`` blocks until the background memory copy finishes
|
|
210
|
+
and the returned snapshot is ``status="ready"``. Set to
|
|
211
|
+
``False`` to return as soon as the source resumes (~10 ms);
|
|
212
|
+
the snapshot reaches ``status="ready"`` later — poll
|
|
213
|
+
:meth:`list_snapshots` to detect completion.
|
|
171
214
|
|
|
172
215
|
The source sandbox is paused for the duration of the snapshot
|
|
173
|
-
write — typically 0.5-8 s for Full, ~200 ms for Diff
|
|
174
|
-
resumed. The returned snapshot is independent
|
|
175
|
-
lifecycle.
|
|
216
|
+
write — typically 0.5-8 s for Full, ~200 ms for Diff, sub-50 ms
|
|
217
|
+
for Live — then resumed. The returned snapshot is independent
|
|
218
|
+
of the source's lifecycle.
|
|
176
219
|
|
|
177
220
|
Returns a SnapshotInfo dict; pass its ``tag`` to
|
|
178
221
|
``spawn_sandboxes`` to fork grandchildren from the branch.
|
|
@@ -180,10 +223,19 @@ class Controller:
|
|
|
180
223
|
body: dict[str, Any] = {}
|
|
181
224
|
if tag is not None:
|
|
182
225
|
body["tag"] = tag
|
|
183
|
-
|
|
226
|
+
# Prefer canonical `mode` when set; fall back to legacy `diff`
|
|
227
|
+
# so older daemons keep working unchanged.
|
|
228
|
+
if mode is not None:
|
|
229
|
+
body["mode"] = mode
|
|
230
|
+
elif diff:
|
|
184
231
|
body["diff"] = True
|
|
185
232
|
if measure_diff:
|
|
186
233
|
body["measure_diff"] = True
|
|
234
|
+
# `wait=True` is the daemon default; only send when the caller
|
|
235
|
+
# opted into fire-and-forget so the body stays minimal against
|
|
236
|
+
# daemons that don't recognize the field.
|
|
237
|
+
if not wait:
|
|
238
|
+
body["wait"] = False
|
|
187
239
|
return self._request("POST", f"/v1/sandboxes/{sandbox_id}/branch", body)
|
|
188
240
|
|
|
189
241
|
def exec_command(
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "forkd"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.2"
|
|
8
8
|
description = "Open-source fork-on-write microVM sandbox primitive (E2B-compatible surface)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{name = "Deeplethe", email = "info@deeplethe.com"}]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|