mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-08-08 04:43:34 +00:00
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e8566db8ee
|
fix(persistency): own Persistency per node instead of a process-global singleton (#4109)
* fix(persistency): own Persistency per node instead of a process-global singleton
The Persistency singleton (gPersistency) was allocated on whichever FFI
thread first ran waku.start; under --mm:refc its memory belonged to that
thread's heap, so a second library context adopting it read a foreign
heap (SIGSEGV in sdsPersistence -> openJob -> tables.rawGet), one
context's stop stole the other's SDS persistence, and a destroyed
context poisoned re-init with a different local-storage-path.
- remove the singleton (instance/reset/gPersistency); Persistency.new is
the public constructor, no lock needed (instances are thread-confined)
- own the instance as Waku.persistency: created and provided in
waku.start, cleared and closed in waku.stop on the owning thread
- expose it via a sync GetPersistency RequestBroker scoped to the node's
BrokerContext; sdsPersistence resolves through it (same-thread ref
return, no marshalling)
- add InMemoryStoragePath (":memory:") support: private in-memory SQLite
per job worker, for tests
- rewrite test_singleton as per-instance + broker coverage; rewrite
test_thread_affinity from a known-failing UB repro into a regression
guard (two in-memory jobs, worker spinup/teardown, cross-thread broker
denial) and register it in test_all; migrate remaining tests to
new/close; the FFI lifecycle test's stop-steals and different-paths
cases now pass against the real dylib
The FFI destroy-without-stop teardown gap remains tracked in #4108.
Fixes #4103
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(persistency): create the instance only after startup fully succeeds
waku.start has many error return paths; creating Persistency early meant
every one of them left the field set and the GetPersistency provider
installed with no teardown. Persistency.new is inert (no threads or
files until the first openJob) and every consumer runs post-start, so
creating and providing it as the last startup step removes the need for
any error-path cleanup entirely.
Addresses PR #4109 review feedback.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(persistency): create early for startup-stage restores, tear down on failed start
Creating the instance as the last startup step made it impossible for
any stage of start to restore persisted data (e.g. a future store-state
restore). Restore the original ordering -- create and provide the
instance first -- and cover every error return path of waku.start with a
success-flag defer that clears the provider and closes the instance.
Teardown is factored into closePersistency, shared by stop and the
failed-start path.
Addresses PR #4109 review discussion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(persistency): address remaining Copilot review findings
- document that Persistency instances are thread-confined (not
thread-safe) on the type itself, pointing at the GetPersistency broker
as the sanctioned access path
- use tryRemoveFile for the FFI test's log cleanup so an unremovable
file cannot fail the test for unrelated reasons
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Fix comment
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
ce918b0819
|
chore: replace Option with Opt (#4035)
* change all usage of std.options.Option[T] to results.Opt[T] * fix broken apps and examples (to validate refactor) * removed all std/options code added for libp2p v2 migration * add broker Opt codec to persistency/backend_comm.nim * add a readValue overload for Opt[T] in tools/confutils/cli_args.nim * keep Option where required (Presto, confutils' config_file.nim) * Change generateRlnProof error handling * Fix imports |
||
|
|
42ccb5c673
|
chore: replace ReliableChannel sendhandler hack (#3994)
* squash original commits and rebase to master: removed sendHandler and replaced by MessagingSend BrokerRequest * Needed to adapt to new messaging source structure to avoid cyclic imports * Relocate MessagingSend request broker and eliminate api/requests * fix ci fails |
||
|
|
3b03ca29b1
|
refactor: introduce proper logos_delivery layers folder structure (#3935)
Co-authored-by: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> |
||
|
|
deb6929670
|
feat: introduce SDS persistency glue (#3913)
* persistency: follow nim-sds 0.3.0 snapshot persistence contract nim-sds 0.3.0 replaced the ~14 fine-grained per-row Persistence callbacks with a 5-proc snapshot model (saveChannelMeta / updateHistory / loadChannel / dropChannel / setRetrievalHint), all returning Future[Result[...]]. Rewrite waku/persistency/sds_persistency.nim accordingly: - ChannelMeta is stored as one blob per channel; the message log as append/evict rows. Categories collapse from 7 to 2 (sds.meta, sds.log). - Blob transform uses nim-sds' own codecs: snapshot_codec (schema-versioned protobuf) for ChannelMeta, the SDS wire codec for SdsMessage log rows. The generic payload_codec/BlobCodec path is retired (removed payload_codec.nim and test_blob_codec.nim). - setRetrievalHint is a deliberate no-op: persisted hints are never read back (loadChannel/ChannelMeta carry none; hints are supplied live via the onRetrievalHint provider). The closure stays because the field is required. - Fix the module import spelling (srcDir="sds" => bare module paths), which the previous adapter got wrong and never compiled against the locked deps. Add tests/persistency/test_sds_persistency.nim (round-trip, empty-load, evict, drop) replacing test_blob_codec in test_all. Full persistency suite passes 74/74 under both refc and ORC. * Bump to latest nim-sds and nim-brokers 3.1.1 * Update with latest nim-sds changes - removal of setRetrievalHints - not needed |
||
|
|
42e0aa43d1
|
feat: persistency (#3880)
* persistency: per-job SQLite-backed storage layer (singleton, brokered)
Adds a backend-neutral CRUD library at waku/persistency/, plus the
nim-brokers dependency swap that enables it.
Architecture (ports-and-adapters):
* Persistency: process-wide singleton, one root directory.
* Job: one tenant, one DB file, one worker thread, one BrokerContext.
* Backend: SQLite via waku/common/databases/db_sqlite. Uniform schema
kv(category BLOB, key BLOB, payload BLOB) PRIMARY KEY (category, key)
WITHOUT ROWID, WAL mode.
* Writes are fire-and-forget via EventBroker(mt) PersistEvent.
* Reads are async via five RequestBroker(mt) shapes (KvGet, KvExists,
KvScan, KvCount, KvDelete). Reads return Result[T, PersistencyError].
* One storage thread per job; tenants isolated by BrokerContext.
Public surface (waku/persistency/persistency.nim):
Persistency.instance(rootDir) / Persistency.instance() / Persistency.reset()
p.openJob(id) / p.closeJob(id) / p.dropJob(id) / p.close()
p.job(id) / p[id] / p.hasJob(id)
Writes (Job form & string-id form, fire-and-forget):
persist / persistPut / persistDelete / persistEncoded
Reads (Job form & string-id form, async Result):
get / exists / scan / scanPrefix / count / deleteAcked
Key & payload encoding (keys.nim, payload.nim):
* encodePart family + variadic key(...) / payload(...) macros +
single-value toKey / toPayload.
* Primitives: string and openArray[byte] are 2-byte BE length + bytes;
int{8..64} are sign-flipped 8-byte BE; uint{16..64} are 8-byte BE;
bool/byte/char are 1 byte; enums are int64(ord(v)).
* Generic encodePart[T: tuple | object] recurses through fields() so
any composite Nim type is encodable without ceremony.
* Stable across Nim/C compiler upgrades: no sizeof, no memcpy, no
cast on pointers, no host-endianness dependency.
* `rawKey(bytes)` + `persistPut(..., openArray[byte])` let callers
bypass the built-in encoder with their own format (CBOR, protobuf...).
Lifecycle:
* Persistency.new is private; Persistency.instance is the only public
constructor. Same rootDir is idempotent; conflicting rootDir is
peInvalidArgument. Persistency.reset for test/restart paths.
* openJob opens-or-creates the per-job SQLite file; an existing file
is reused with its data preserved.
* Teardown integration: Persistency.instance registers a Teardown
MultiRequestBroker provider that closes all jobs and clears the
singleton slot when Waku.stop() issues Teardown.request.
Internal layering:
types.nim pure value types (Key, KeyRange, KvRow, TxOp,
PersistencyError)
keys.nim encodePart primitives + key(...) macro
payload.nim toPayload + payload(...) macro
schema.nim CREATE TABLE + connection pragmas + user_version
backend_sqlite.nim KvBackend, applyOps (single source of write SQL),
getOne/existsOne/deleteOne, scanRange (asc/desc,
half-open ranges, open-ended stop), countRange
backend_comm.nim EventBroker(mt) PersistEvent + 5 RequestBroker(mt)
declarations; encodeErr/decodeErr boundary helpers
backend_thread.nim startStorageThread / stopStorageThread (shared
allocShared0 arg, cstring dbPath, atomic
ready/shutdown flags); per-thread provider
registration
persistency.nim Persistency + Job types, singleton state, public
facade
../requests/lifecycle_requests.nim
Teardown MultiRequestBroker
Tests (69 cases, all passing):
test_keys.nim sort-order invariants (length-prefix strings,
sign-flipped ints, composite tuples, prefix
range)
test_backend.nim round-trip / replace / delete-return-value /
batched atomicity / asc-desc-half-open-open-
ended scans / category isolation / batch
txDelete
test_lifecycle.nim open-or-create rootDir / non-dir collision /
reopen across sessions / idempotent openJob /
two-tenant parallel isolation / closeJob joins
worker / dropJob removes file / acked delete
test_facade.nim put-then-get / atomic batch / scanPrefix
asc/desc / deleteAcked hit-miss /
fire-and-forget delete / two-tenant facade
isolation
test_encoding.nim tuple/named-tuple/object keys, embedded Key,
enum encoding, field-major composite sort,
payload struct encoding, end-to-end struct
round-trip through SQLite
test_string_lookup.nim peJobNotFound semantics / hasJob / subscript /
persistPut+get via id / reads short-circuit /
writes drop+warn / persistEncoded via id /
scan parity Job-ref vs id
test_singleton.nim idempotent same-rootDir / different-rootDir
rejection / no-arg instance lifecycle / reset
retargets / reset idempotence / Teardown.request
end-to-end
Prerequisite delivered in the same series: replace the in-tree broker
implementation with the external nim-brokers package; update all
broker call-sites (waku_filter_v2, waku_relay, waku_rln_relay,
delivery_service, peer_manager, requests/*, factory/*, api tests, etc.)
to the new package API; chat2 made to compile again.
Note: SDS adapter (Phase 5 of the design) is deferred -- nim-sds is
still developed side-by-side and the persistency layer is intentionally
SDS-agnostic.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* persistency: pin nim-brokers by URL+commit (workaround for stale registry)
The bare `brokers >= 2.0.1` form cannot resolve on machines where the
local nimble SAT solver enumerates only the registry-recorded 0.1.0 for
brokers. The nim-lang/packages entry for `brokers` carries no per-tag
metadata (only the URL), so until that registry entry is refreshed the
SAT solver clamps the available-versions list to 0.1.0 and rejects the
>= 2.0.1 constraint -- even though pkgs2 and pkgcache both have v2.0.1
cloned locally.
Pinning by URL+commit bypasses the registry path entirely. Inline
comment in waku.nimble documents the situation and the path back to
the bare form once nim-lang/packages is updated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* persistency: nph format pass
Run `nph` on all 57 Nim files touched by this PR. Pure formatting:
17 files re-styled, no semantic change. Suite still 69/69.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Fix build, add local-storage-path config, lazy init of Persistency from Waku start
* fix: fix nix deps
* fixes for nix build, regenerate deps
* reverting accidental dependency changes
* Fixing deps
* Apply suggestions from code review
Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
* persistency tests: migrate to suite / asyncTest / await
Match the in-tree test convention (procSuite -> suite, sync test +
waitFor -> asyncTest + await):
- procSuite "X": -> suite "X":
- For tests doing async work: test -> asyncTest, waitFor -> await.
- Poll helpers (proc waitFor(t: Job, ...) in test_lifecycle.nim,
proc waitUntilExists(...) in test_facade.nim and
test_string_lookup.nim) -> Future[bool] {.async.}, internal
`waitFor X` -> `await X`, internal `sleep(N)` ->
`await sleepAsync(chronos.milliseconds(N))`.
- Renamed test_lifecycle.nim's helper proc from `waitFor(t: Job, ...)`
-> `pollExists(t: Job, ...)`; the previous name shadowed
chronos.waitFor in the chronos macro expansion.
- `chronos.milliseconds(N)` explicitly qualified because `std/times`
also exports `milliseconds` (returning TimeInterval, not Duration).
- `check await x` -> `let okN = await x; check okN` to dodge chronos's
"yield in expr not lowered" with await-as-macro-argument.
- `(await x).foo()` -> `let awN = await x; ... awN.foo() ...` for the
same reason.
waku/persistency/persistency.nim: nph also pulled the proc signatures
across multiple lines; restored explicit `Future[void] {.async.}`
return types after the colon (an intermediate nph pass had elided them).
Suite: 71 / 71 OK against the new async write surface.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* use idiomatic valueOr instead of ifs
* Reworked persistency shutdown, remove not necessary teardown mechanism
* Use const for DefaultStoragePath
* format to follow coding guidelines - no use of result and explicit returns - no functional change
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
|