manta-node 0.6b5.dev705__py3-none-any.whl → 0.6b5.dev706__py3-none-any.whl
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.
- manta_node/cli/_version_generated.py +2 -2
- manta_node/supervisor/lifecycle.py +23 -0
- manta_node/supervisor/switch.py +71 -0
- {manta_node-0.6b5.dev705.dist-info → manta_node-0.6b5.dev706.dist-info}/METADATA +1 -1
- {manta_node-0.6b5.dev705.dist-info → manta_node-0.6b5.dev706.dist-info}/RECORD +9 -9
- {manta_node-0.6b5.dev705.dist-info → manta_node-0.6b5.dev706.dist-info}/WHEEL +0 -0
- {manta_node-0.6b5.dev705.dist-info → manta_node-0.6b5.dev706.dist-info}/entry_points.txt +0 -0
- {manta_node-0.6b5.dev705.dist-info → manta_node-0.6b5.dev706.dist-info}/licenses/LICENSE +0 -0
- {manta_node-0.6b5.dev705.dist-info → manta_node-0.6b5.dev706.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ This file is auto-generated at build time by scripts/generate_version.py.
|
|
|
4
4
|
Do not edit manually.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "2026.09.24.
|
|
7
|
+
__version__ = "2026.09.24.8d51d71c"
|
|
8
8
|
__build_date__ = "2026.09.24"
|
|
9
|
-
__commit_id__ = "
|
|
9
|
+
__commit_id__ = "8d51d71c"
|
|
10
10
|
__package_version__ = "0.6b5"
|
|
@@ -28,6 +28,11 @@ from .bounds import Bounds
|
|
|
28
28
|
from .inflight import InFlight, clear_inflight, deadline_from_now, write_inflight
|
|
29
29
|
from .switch import VersionTreeError
|
|
30
30
|
|
|
31
|
+
# The free-space floor to stage a version dir. A version dir holds a full
|
|
32
|
+
# dependency closure, so the check refuses well before the disk is full rather
|
|
33
|
+
# than half-staging (NF-12). Operator-overridable via `run_switch`'s argument.
|
|
34
|
+
MIN_FREE_BYTES = 500 * 1024 * 1024
|
|
35
|
+
|
|
31
36
|
|
|
32
37
|
class LifecycleError(Exception):
|
|
33
38
|
"""A lifecycle step failed; the node stays on its current version (NF-3)."""
|
|
@@ -88,6 +93,7 @@ def run_switch(
|
|
|
88
93
|
is_back: ReturnProbe,
|
|
89
94
|
bounds: Bounds | None = None,
|
|
90
95
|
now: Callable[[], float] = time.time,
|
|
96
|
+
min_free_bytes: int = MIN_FREE_BYTES,
|
|
91
97
|
) -> SwitchOutcome:
|
|
92
98
|
"""Run the lifecycle for one request and return its terminal outcome.
|
|
93
99
|
|
|
@@ -121,6 +127,16 @@ def run_switch(
|
|
|
121
127
|
if not _within(bounds.verify, lambda: verify(candidate_dir, candidate_python)):
|
|
122
128
|
return _outcome(request, SeamState.FAILED, "verification failed (no switch)")
|
|
123
129
|
|
|
130
|
+
# FREE SPACE — refuse before staging when there is no room for a full version
|
|
131
|
+
# dir (NF-12, §6.2). Refusing here, before any write, is what stops a
|
|
132
|
+
# half-staged tree: the node stays on its current version.
|
|
133
|
+
if not version_tree.has_room_for(min_free_bytes):
|
|
134
|
+
return _outcome(
|
|
135
|
+
request,
|
|
136
|
+
SeamState.REFUSED,
|
|
137
|
+
"insufficient free space to stage a version dir",
|
|
138
|
+
)
|
|
139
|
+
|
|
124
140
|
# STAGE — materialise the candidate's version dir (idempotent), bounded.
|
|
125
141
|
staged: dict = {}
|
|
126
142
|
|
|
@@ -161,6 +177,13 @@ def run_switch(
|
|
|
161
177
|
|
|
162
178
|
if is_back(record.deadline_epoch):
|
|
163
179
|
clear_inflight()
|
|
180
|
+
# Reclaim on a SUCCESSFUL switch (NF-12/B-34): the tree stays bounded, and
|
|
181
|
+
# the current and last-good versions are never removed. No separate
|
|
182
|
+
# sweeper: reclamation rides the switch that made a version superseded.
|
|
183
|
+
protect = {target}
|
|
184
|
+
if last_good_dir is not None:
|
|
185
|
+
protect.add(last_good_dir)
|
|
186
|
+
version_tree.reclaim(bounds.retention_dirs, protect)
|
|
164
187
|
return _outcome(
|
|
165
188
|
request,
|
|
166
189
|
SeamState.REPORTING,
|
manta_node/supervisor/switch.py
CHANGED
|
@@ -22,6 +22,8 @@ the token, config or datasets.
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
24
|
import os
|
|
25
|
+
import shutil
|
|
26
|
+
import sys
|
|
25
27
|
from dataclasses import dataclass
|
|
26
28
|
from datetime import datetime, timezone
|
|
27
29
|
from importlib.metadata import PackageNotFoundError, version
|
|
@@ -199,3 +201,72 @@ def is_pointer_target(target: Path) -> bool:
|
|
|
199
201
|
"""True when ``current`` resolves to ``target``."""
|
|
200
202
|
link = current_link()
|
|
201
203
|
return link.is_symlink() and Path(os.path.realpath(link)) == target
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def list_versions() -> list[Path]:
|
|
207
|
+
"""The version dirs, oldest first.
|
|
208
|
+
|
|
209
|
+
Ordered by the manifest's ``created`` (a dir with no readable manifest sorts
|
|
210
|
+
first, so a corrupt one is reclaimed before a good one). Used by retention to
|
|
211
|
+
pick what to reclaim.
|
|
212
|
+
"""
|
|
213
|
+
root = versions_dir()
|
|
214
|
+
if not root.is_dir():
|
|
215
|
+
return []
|
|
216
|
+
|
|
217
|
+
def created(p: Path) -> str:
|
|
218
|
+
manifest = read_manifest(p)
|
|
219
|
+
return manifest.created if manifest else ""
|
|
220
|
+
|
|
221
|
+
dirs = [p for p in root.iterdir() if p.is_dir()]
|
|
222
|
+
return sorted(dirs, key=created)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def reclaim(retention_dirs: int, protect: set[Path]) -> list[Path]:
|
|
226
|
+
"""Remove the oldest versions beyond ``retention_dirs``, never a protected one.
|
|
227
|
+
|
|
228
|
+
NF-12/B-34: the version tree stays bounded, but the **current** and last-good
|
|
229
|
+
versions are never removed — ``protect`` names them. Returns the removed dirs.
|
|
230
|
+
Called on a successful switch, so there is no separate sweeper to start.
|
|
231
|
+
"""
|
|
232
|
+
versions = list_versions()
|
|
233
|
+
protected = {os.path.realpath(p) for p in protect}
|
|
234
|
+
# Oldest first; drop the front until the count is within the bound, skipping
|
|
235
|
+
# a protected dir (do not count it as removable, but it still occupies a slot).
|
|
236
|
+
removed: list[Path] = []
|
|
237
|
+
keep = max(retention_dirs, 2) # current + last good is the floor
|
|
238
|
+
for candidate in versions:
|
|
239
|
+
if len(versions) - len(removed) <= keep:
|
|
240
|
+
break
|
|
241
|
+
if os.path.realpath(candidate) in protected:
|
|
242
|
+
continue
|
|
243
|
+
try:
|
|
244
|
+
for child in candidate.iterdir():
|
|
245
|
+
if child.is_dir():
|
|
246
|
+
shutil.rmtree(child)
|
|
247
|
+
else:
|
|
248
|
+
child.unlink()
|
|
249
|
+
candidate.rmdir()
|
|
250
|
+
removed.append(candidate)
|
|
251
|
+
except OSError as exc:
|
|
252
|
+
# A dir we cannot remove stays: retention is best-effort on a live
|
|
253
|
+
# node, and failing the switch over a stale dir would be worse.
|
|
254
|
+
print(f"retention: could not reclaim {candidate}: {exc}", file=sys.stderr)
|
|
255
|
+
return removed
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def has_room_for(min_bytes: int) -> bool:
|
|
259
|
+
"""True when the version tree's filesystem has at least ``min_bytes`` free.
|
|
260
|
+
|
|
261
|
+
The free-space refusal (NF-12, mechanism §6.2): a node with no room to stage
|
|
262
|
+
a full version dir refuses the update rather than half-staging. The caller
|
|
263
|
+
passes the candidate's estimated size.
|
|
264
|
+
"""
|
|
265
|
+
root = versions_dir()
|
|
266
|
+
# Check the nearest existing ancestor: the tree may not exist yet on a fresh
|
|
267
|
+
# node, and the capacity is the filesystem's either way.
|
|
268
|
+
probe = root
|
|
269
|
+
while not probe.exists() and probe != probe.parent:
|
|
270
|
+
probe = probe.parent
|
|
271
|
+
free = shutil.disk_usage(probe).free
|
|
272
|
+
return free >= min_bytes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: manta_node
|
|
3
|
-
Version: 0.6b5.
|
|
3
|
+
Version: 0.6b5.dev706
|
|
4
4
|
Summary: Node side software of the Manta platform. It is responsible for the communication with the Manta Core and the execution of the tasks.
|
|
5
5
|
Author-email: Hugo Miralles <hugo.miralles@manta-tech.io>, Matthew Thompson <matthew.thompson@manta-tech.io>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -6,7 +6,7 @@ manta_node/task_manager.py,sha256=xRE-yKdUW0FFR8vtX1jDwl1AxTbqVD_JS7QVR62GA00,38
|
|
|
6
6
|
manta_node/tasks.py,sha256=o837Hi-KFVJg9LF5iOtE8oD6UuTOfrEPWR-JOdhRGeY,6983
|
|
7
7
|
manta_node/utils.py,sha256=Hw4Iw2jYQYsfVLVJuBMt-_rMFBeml3nCDE2jiiXc8YM,1155
|
|
8
8
|
manta_node/cli/__init__.py,sha256=arzO3mXDJ-E2yeeytbZfN7mCswwxdQ43_QjyeL2E5yE,134
|
|
9
|
-
manta_node/cli/_version_generated.py,sha256=
|
|
9
|
+
manta_node/cli/_version_generated.py,sha256=rTGRherNt_ty7j_gNSOWg1VAt6h2GPc4Yfxo9cEWRio,275
|
|
10
10
|
manta_node/cli/config_manager.py,sha256=BCju9zqzraviL3KrzRnB-vZQUY__Q5kuEqb7EdB8YdI,4409
|
|
11
11
|
manta_node/cli/main.py,sha256=dZa6zrypWBvpN8hd4qpxevvlyNFhxKINCg1537NJ36w,4318
|
|
12
12
|
manta_node/cli/version.py,sha256=3lrnIWpOosszBN-VsCBVLxDgpvCC7IB0aDIKx_3e7hI,3115
|
|
@@ -56,14 +56,14 @@ manta_node/supervisor/__init__.py,sha256=kgdoNce1tM4e7jvdxkdmnNJV1L92-NI2cRfYSdm
|
|
|
56
56
|
manta_node/supervisor/bounds.py,sha256=MlUfj0tYY-US348JsxYA-Ph5pSpgoOPlRdVTwmrPtZA,3181
|
|
57
57
|
manta_node/supervisor/executor.py,sha256=a0JafVoTmtbIu87nwUtj08KAC-Q-u0Ajdn_ptyu9yoc,6833
|
|
58
58
|
manta_node/supervisor/inflight.py,sha256=JOqwXYM928fpcQtYdoK7596eAg28KM70bh85cyQgX3Q,2663
|
|
59
|
-
manta_node/supervisor/lifecycle.py,sha256=
|
|
59
|
+
manta_node/supervisor/lifecycle.py,sha256=GDy7d7MHxhabvTRoIkAL-_n0oja-GpmVWYAzOehP_DI,8551
|
|
60
60
|
manta_node/supervisor/process.py,sha256=mWd2C4-S8NpupcLp0YbBEYmqQUQbrfMAZi5TF9UQ_cM,17504
|
|
61
61
|
manta_node/supervisor/records.py,sha256=fUlL1SfmWpGnCbJ9956cuy0H3a7-aEF-B-naqbJiYoU,6405
|
|
62
62
|
manta_node/supervisor/seam.py,sha256=HomMFTDbc0dZQ9VrfGVhQxjiU7E23-zwyjZnLsnq6dc,8031
|
|
63
|
-
manta_node/supervisor/switch.py,sha256=
|
|
64
|
-
manta_node-0.6b5.
|
|
65
|
-
manta_node-0.6b5.
|
|
66
|
-
manta_node-0.6b5.
|
|
67
|
-
manta_node-0.6b5.
|
|
68
|
-
manta_node-0.6b5.
|
|
69
|
-
manta_node-0.6b5.
|
|
63
|
+
manta_node/supervisor/switch.py,sha256=HQcNULUf6JafDGoKIh1mrw-4m9pxvz1hMLUPnwkY6mc,10173
|
|
64
|
+
manta_node-0.6b5.dev706.dist-info/licenses/LICENSE,sha256=9mBgLhiB9goQPQjg9XQJ6FjgVxYw9Q8lyOZYkPGwF_c,34484
|
|
65
|
+
manta_node-0.6b5.dev706.dist-info/METADATA,sha256=uSttKoedT1orqAsgzeEQzdiwXS8i8HW1Jdv2ni9q3rE,4231
|
|
66
|
+
manta_node-0.6b5.dev706.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
67
|
+
manta_node-0.6b5.dev706.dist-info/entry_points.txt,sha256=uCwggRApalLEsYs1YxwTBN0-e9oMJAkMoBp01HaSdoY,110
|
|
68
|
+
manta_node-0.6b5.dev706.dist-info/top_level.txt,sha256=nbT5J5WETuXM9UPoQckl29uUOq8wMYdRb9QDx5kAFeo,11
|
|
69
|
+
manta_node-0.6b5.dev706.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|