Commit Graph

4 Commits

Author SHA1 Message Date
Hamed 8eb58a4a14 perf(ip-sync): avoid redundant client IP reads and writes (#6930)
The access-log scanner and the cross-node merge stored the same IP list in
opposite orders, so neither saw a row as unchanged, and the merge re-read
every preloaded row and re-upserted every attribution row each sync cycle.
All writers now share one canonical encoder (timestamp, then IP ascending),
the first CAS is seeded from the preload, and identical attribution rows are
skipped. A create race between the scanner and node sync now merges into the
winning row instead of dropping the loser's IPs, which on PostgreSQL also
aborted the scanner's whole scan transaction.

Closes #6927
2026-10-25 14:13:18 +01:00
Hamed 64a7697f56 perf(traffic): skip unchanged global writes between heartbeats (#6931)
* perf(traffic): skip unchanged global writes between heartbeats

Persist directional usage changes immediately, including lower resets, while
refreshing identical global totals only at an inclusive one-hour heartbeat.
Use the GORM clock consistently for the existing 24-hour freshness window and
preserve local-only snapshots, quota enforcement, and downstream forwarding.

Fixes #6928

* docs(traffic): describe persisted global heartbeat timestamps

Replace the stale every-push model comment with the change-or-hourly-heartbeat
rule. Keep the local-counter separation, delta accounting, MAX fold and reset
semantics explicit without treating UpdatedAt as a last-push timestamp.

Address the nonblocking review feedback on PR #6931 without rewriting
published history.

Refs #6928
2026-10-25 08:44:05 +01:00
MHSanaei dae91276aa chore(nodes): run the master+node scopes in parallel and document both layers
Each enrollment scope owns its panels, ports and temp dirs, so the two run
side by side; the only shared state, the process-global database handle the
harness borrows for setup and for simulating a lost inbound, is now behind a
mutex. On Linux the suite drops from 188s to 95s.

CLAUDE.md now names the fast contract layer (node_contract_test.go, in
make test-go) next to the multi-tick nodee2e layer.
2026-10-05 13:30:18 +02:00
MHSanaei f843fe5570 chore(nodes): add a master+node end-to-end harness and CI job
Node sync had no test with two real panels: the single-panel tests either
call the node's controller in-process or hand-set the node-sync scope, so
823db059 shipped a regression no test could see (an admin-token node
dropped every client and enable flag its master pushed).

internal/nodee2e starts a master and a node as separate panel processes
(the DB is a process-wide global, so one process cannot be both) and walks
17 operations per enrollment scope (admin token, node-sync token): adopt,
create/edit on the master, small and bulk attach, client disable, detach,
client delete, inbound disable, traffic pull and reset, node-side delete
mirrored centrally (#6219), master-side delete, node down, node-lost
inbound re-created, create/edit while down, node disabled on the master,
and selected sync mode leaving unselected inbounds alone.

Against the build before 2ffc694a it fails 6 cells for an admin-token node
and 1 for a node-sync one; on main all 34 pass, on Windows and on Linux.
`make node-e2e` builds a stub-dist binary and runs it; ci.yml runs it as
its own job where a SKIP fails the build. Xray is not started, so cells
assert the node's stored state, not traffic through the core.
2026-10-05 13:14:30 +02:00