morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
morph::offline::InMemoryReplayLedger Class Reference

In-memory implementation of IReplayLedger, owned by one executor. More...

#include <replay_ledger.hpp>

Inheritance diagram for morph::offline::InMemoryReplayLedger:
morph::offline::IReplayLedger

Public Member Functions

 InMemoryReplayLedger (::morph::exec::IExecutor &owner)
 Constructs an empty ledger belonging to owner.
Public Member Functions inherited from morph::offline::IReplayLedger
std::optional< std::string > lookup (std::string_view scope, std::string_view opId) const
 Reports whether opId within scope has already been decided.
void record (std::string_view scope, std::string_view opId, std::string payload)
 Records that opId within scope has been decided, with payload attached.
::morph::async::Completion< std::optional< std::string > > lookup (::morph::exec::IExecutor &replyExec, std::string_view scope, std::string_view opId) const
 Reports whether opId within scope has already been decided, looked up on the ledger's owner and delivered on replyExec.

Protected Member Functions

std::optional< std::string > doLookup (std::string_view scope, std::string_view opId) const override
 Looks up opId within scope in the in-memory map. On the owner.
void doRecord (std::string_view scope, std::string_view opId, std::string payload) override
 Records opId within scope in the in-memory map, unless already present (first-write-wins). On the owner; posted there from anywhere else.
::morph::async::Completion< std::optional< std::string > > askLookup (::morph::exec::IExecutor &replyExec, std::string scope, std::string opId) const override
 Looks up on the owner, answered on replyExec.

Detailed Description

In-memory implementation of IReplayLedger, owned by one executor.

Suitable for testing and for a host with no durability requirement. Mirrors morph::offline::InMemoryOfflineQueue's shape. Not durable across a process restart, and — since it is not backed by any real transaction — not a stand-in for record()'s atomicity requirement: a real implementation must be backed by the same store and transaction as the write it guards.

One owner
The entries belong to the executor given at construction, which must run one task at a time — the executor the guarded writes run on, so a lookup() and the record() after it are one check-then-set. lookup() answers only there; record() runs there, posted from anywhere else; a caller elsewhere looks up through lookup(replyExec, scope, opId).

Definition at line 216 of file replay_ledger.hpp.

Constructor & Destructor Documentation

◆ InMemoryReplayLedger()

morph::offline::InMemoryReplayLedger::InMemoryReplayLedger ( ::morph::exec::IExecutor & owner)
inlineexplicit

Constructs an empty ledger belonging to owner.

Parameters
ownerThe executor every access runs on; must run one task at a time. Borrowed: it must outlive this ledger and run what it posts.

Definition at line 221 of file replay_ledger.hpp.

Member Function Documentation

◆ doLookup()

std::optional< std::string > morph::offline::InMemoryReplayLedger::doLookup ( std::string_view scope,
std::string_view opId ) const
inlinenodiscardoverrideprotectedvirtual

Looks up opId within scope in the in-memory map. On the owner.

The two std::string constructions below are deliberate
They materialise the key purely to probe an ordered map that could take a transparent comparator instead. That was profiled rather than fixed. Measured with clang 22 -O2, a counting operator new, 2e6 iterations per row:
/// -- allocations per lookup() --
/// scope=bookmarks              ( 9) id=CreateSwimlane       (14) : 0.00
/// scope=bookmarks              ( 9) id=CreateSwimlane-0001  (19) : 1.00
/// scope=bookmarks-import-scope (22) id=CreateSwimlane-0001  (19) : 2.00
///
/// -- ns per lookup(), single thread --
/// both inside libstdc++'s 15-char SSO buffer : 28.2 ns
/// both past it                               : 31.6 ns
/// 

So the cost is real and id-length-dependent. What parks it is the call census, not the size: InMemoryReplayLedger is constructed in one file in this tree, tests/test_replay_ledger.cpp, and in no shipping code at all. The only production IReplayLedger::lookup() call (examples/bookmarks/src/models/bookmark_model.cpp:737, once per ImportBookmarks) runs against BookmarksReplayLedger, whose own doLookup is an ODBC round-trip – next to which 3 ns is not measurable.

It becomes worth fixing the moment a per-request caller of this class appears; the fix is then a transparent comparator on the map, std::map's is_transparent flavour rather than core/registry.hpp's hash-and-equality pair (which serves an unordered_map and does not apply here).

Parameters
scopeCaller-chosen partition.
opIdThe operation id to look up; never empty here.
Returns
The payload recorded with opId, or std::nullopt if none.

Implements morph::offline::IReplayLedger.

Definition at line 263 of file replay_ledger.hpp.

◆ doRecord()

void morph::offline::InMemoryReplayLedger::doRecord ( std::string_view scope,
std::string_view opId,
std::string payload )
inlineoverrideprotectedvirtual

Records opId within scope in the in-memory map, unless already present (first-write-wins). On the owner; posted there from anywhere else.

Parameters
scopeCaller-chosen partition.
opIdThe operation id being recorded; never empty here.
payloadOpaque payload to associate with opId.

Implements morph::offline::IReplayLedger.

Definition at line 274 of file replay_ledger.hpp.

◆ askLookup()

::morph::async::Completion< std::optional< std::string > > morph::offline::InMemoryReplayLedger::askLookup ( ::morph::exec::IExecutor & replyExec,
std::string scope,
std::string opId ) const
inlinenodiscardoverrideprotectedvirtual

Looks up on the owner, answered on replyExec.

Parameters
replyExecWhere the answer is delivered.
scopeCaller-chosen partition.
opIdThe operation id to look up; never empty here.
Returns
The payload recorded with opId, or std::nullopt.

Reimplemented from morph::offline::IReplayLedger.

Definition at line 290 of file replay_ledger.hpp.


The documentation for this class was generated from the following file: