aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node')
-rw-r--r--packages/meshbay-node/src/meshbay_node/config.py35
-rw-r--r--packages/meshbay-node/tests/test_connection_processes.py20
2 files changed, 43 insertions, 12 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/config.py b/packages/meshbay-node/src/meshbay_node/config.py
index c5596f1..d46ab8c 100644
--- a/packages/meshbay-node/src/meshbay_node/config.py
+++ b/packages/meshbay-node/src/meshbay_node/config.py
@@ -74,13 +74,14 @@ max_concurrent_uploads = 8
# the partial file is deleted.
max_upload_gb = 8
-# How many processes carry the connections of members. At 1 the node does it
+# How many processes carry the connections of members. Left unset: one per core
+# of this machine, up to four, about 85 MB of memory each. At 1 the node does it
# all in one process, on one core: about 35 MB/s summed over every transfer in
-# progress. Above 1 the node starts that many processes for the connections and
-# keeps the rest for itself, so transfers use that many cores, plus part of one
-# for the node. Takes effect for new connections, without a restart. Not above
-# the number of cores of this machine.
-connection_processes = 1
+# progress on Linux, and much less on Windows. Above 1 the node starts that many
+# processes for the connections and keeps the rest for itself, so transfers use
+# that many cores, plus part of one for the node. Takes effect for new
+# connections, without a restart. Not above the number of cores of this machine.
+# connection_processes = 4
# HEVC sources have no browser decoder on most platforms, so streaming one is
# transcoded to H264 rather than the usual free copy — real CPU per viewer.
@@ -202,8 +203,9 @@ class NodeConfig:
# §15.3), so this is what stands between a writable root and a full disk.
max_upload_gb: float = 8.0
# How many processes hold the peer connections. One means this process
- # holds them itself, as it always did. See transport/webrtc/workers.py.
- connection_processes: int = 1
+ # holds them itself. See transport/webrtc/workers.py, and
+ # `default_connection_processes` for why it is not one by default.
+ connection_processes: int = field(default_factory=lambda: default_connection_processes())
# HEVC (and any future codec in media_probe.py's
# BROWSER_INCOMPATIBLE_VIDEO_CODECS) has no decoder in most browsers, so
# streaming it needs a real re-encode to H264 rather than the usual free
@@ -305,6 +307,23 @@ def max_processes() -> int:
return max(1, os.cpu_count() or 1)
+# Above four, a single download no longer gains (docs/MESHBAY_DESIGN.md §5.5:
+# 131 MB/s at four, 150 at eight with the receiving browser the limit), and each
+# process is 85 MB held for the life of the node.
+DEFAULT_CONNECTION_PROCESSES_MAX = 4
+
+
+def default_connection_processes() -> int:
+ """
+ One per core, up to four. It was 1, which starts no process at all: the
+ several-cores path was measured, shipped and reached by no node whose
+ operator had not found the setting, and the lanes of a download all landed
+ on the node's one core — on Windows, where Python's UDP costs most, a
+ download over eight connections was as slow as over one.
+ """
+ return min(DEFAULT_CONNECTION_PROCESSES_MAX, max_processes())
+
+
def _positive(value: object, default: int, name: str) -> int:
"""A count that must be at least one, or the default with a word about it.
diff --git a/packages/meshbay-node/tests/test_connection_processes.py b/packages/meshbay-node/tests/test_connection_processes.py
index ab9dfd3..778da5a 100644
--- a/packages/meshbay-node/tests/test_connection_processes.py
+++ b/packages/meshbay-node/tests/test_connection_processes.py
@@ -13,6 +13,7 @@ not carry.
"""
import asyncio
+import re
import struct
from pathlib import Path
@@ -231,11 +232,21 @@ async def test_one_process_starts_none():
# ── the setting ─────────────────────────────────────────────────────────────
-def test_the_default_is_one_process(tmp_path):
- assert node_settings_defaults()["connection_processes"] == 1
+@pytest.mark.parametrize("cores, expected", [(1, 1), (2, 2), (4, 4), (28, 4)])
+def test_the_default_is_one_per_core_up_to_four(tmp_path, monkeypatch, cores, expected):
+ """It was 1, which starts none: the path was shipped and reached by no node
+ whose operator had not found the setting."""
+ monkeypatch.setattr("meshbay_node.config.max_processes", lambda: cores)
+ assert node_settings_defaults()["connection_processes"] == expected
conf = tmp_path / "node.toml"
conf.write_text('[hub]\nurl = "https://example.invalid"\nusername = "op"\n')
- assert load_config(conf).node.connection_processes == 1
+ assert load_config(conf).node.connection_processes == expected
+
+
+def test_a_new_node_toml_leaves_it_to_the_default(tmp_path):
+ from meshbay_node.config import EXAMPLE_CONFIG
+ assert not re.search(r"^connection_processes\s*=", EXAMPLE_CONFIG, re.M), (
+ "a value written by `init` is a value no later default reaches")
def test_node_toml_cannot_ask_for_more_than_the_cores(tmp_path):
@@ -296,4 +307,5 @@ async def test_a_number_the_machine_cannot_honour_is_refused(state, monkeypatch,
with pytest.raises(ops.OpError):
await ops.set_node_settings(state, {"connection_processes": value})
assert state["webrtc"].asked == []
- assert (await ops.get_node_settings(state))["connection_processes"] == 1
+ assert ((await ops.get_node_settings(state))["connection_processes"]
+ == state["config"].node.connection_processes)