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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forkd
3
- Version: 0.3.4
3
+ Version: 0.5.2
4
4
  Summary: Open-source fork-on-write microVM sandbox primitive (E2B-compatible surface)
5
5
  Author-email: Deeplethe <info@deeplethe.com>
6
6
  License: Apache-2.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.3.4"
18
- __all__ = ["Sandbox", "CommandResult", "Controller", "ControllerError"]
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
- v0.3+: use Firecracker Diff snapshot mode. The source's
160
- pause window collapses to the Diff write only (~200 ms
161
- for an idle source; 6-15× speedup on typical agent
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 then
174
- resumed. The returned snapshot is independent of the source's
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
- if diff:
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(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forkd
3
- Version: 0.3.4
3
+ Version: 0.5.2
4
4
  Summary: Open-source fork-on-write microVM sandbox primitive (E2B-compatible surface)
5
5
  Author-email: Deeplethe <info@deeplethe.com>
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "forkd"
7
- version = "0.3.4"
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