craft: in-memory reference model + client-facing API surface#166
Merged
Conversation
Add a HomeStore-free, in-process reference model of the CRAFT replication
protocol (the server side) so a client can be built and tested against it,
plus the client-facing CRAFT API it exposes.
Public API (home_blocks.hpp): per-replica CRAFT free functions over an opaque
volume_handle -- login / async_write / async_read / keep_alive -- each carrying
a client_hdr {term, commit_lsn, all_committed_lsn}. Addressing is byte-based
(addr/len aligned to lba_size, returned by login and enforced server-side);
sisl::sg_list is the one buffer type both ways (an empty buffer is a zero
write); reads fill the caller's buffer and return a sparse io_extent layout.
Commit is piggybacked via client_hdr.commit_lsn -- there is no standalone
commit verb -- and keep_alive is its term-fenced carrier. The legacy byte
block ops are marked [[deprecated]] (kept as reference).
Model (src/lib/craft/memory/): MemCraftReplica implements the internal
craft_replica backend (journal, per-LBA index, journal-tail overlay,
horizon-clamped sparse reads, term fencing, in-order commit apply);
MemTransport is the in-process network + cold path (fixed leader, login
orchestration) + fault hooks (replica down/up, sub-quorum).
create_memory_volume / make_memory_replica_set wrap each replica behind a
volume_handle (one handle == one replica device; no aggregate handle). The
model links no HomeStore -- its unit-test binary proves it -- and only the
create_memory_volume glue reuses volume (and thus links the engine).
Tests: 15 model unit tests (no HomeStore, no iomgr reactor; ops complete
inline) + 3 end-to-end tests through the public volume_handle API.
Docs: docs/craft/{api,rpcs,README}.md updated to the landed surface.
Also removes the obsolete disabled memory_backend stub.
a8cbce7 to
d7b9848
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The production CRAFT path (
CraftReplDev) is HomeStore-coupled and the wire transport is stillundecided (CRAFT-1), so a client has nothing to build against yet. This adds a HomeStore-free,
in-process reference model of the CRAFT server side -- a correctness oracle a client can be built and
tested against now -- plus the client-facing CRAFT API that model (and, later, production) exposes.
Canonical protocol lives in the CRAFT-Design wiki and
docs/craft/.Blast radius is small: the product IO path is untouched (purely additive), and the only deletion is the
obsolete disabled
memory_backendstub.The API a client builds against (
home_blocks.hpp)Per-replica free functions over the opaque
volume_handle-- one handle == one replica device (aserver in production; an in-process object here). The client does the CRAFT work: assign
dLSN,broadcast the write to each member, tally quorum, route the read to one member.
Design points -- each deliberate; flagging so they don't need re-litigating in review:
client_hdr {term, commit_lsn, all_committed_lsn}on every IO. Commit is piggybacked viacommit_lsn-- there is no standalonecommitverb (matches the design's "commit / keep_alive /piggyback on the next write").
keep_aliveis its dedicated carrier and is term-fenced (a staleclient must not be able to reset the liveness watchdog and stall failover).
addr/len, aligned tolba_size(returned bylogin), enforced server-side withinvalid_argument-- consistent with the existing byte-based block API; byte↔block conversion staysinside the server.
sisl::sg_list(caller/iomgr-owned). An empty buffer is a zerowrite (WRITE_ZEROES) -- no
all_zerosflag. Reads fill the caller'sdestbuffer and return asparse
io_extentlayout (which byte ranges were data vs holes).async_read/async_write/async_unmap) are[[deprecated]], kept asreference; the deprecation is demoted to a warning on the three existing callers via
-Wno-error=deprecated-declarationsso-Werrorstays green.The model (
src/lib/craft/memory/)MemCraftReplica(implements the internalcraft_replica) -- the protocol, and the reviewablemeat:
dLSN→slot journal, per-LBA index, journal-tail overlay, horizon-clamped sparse reads(data / holes / all-zero-collapse in
read_range()), term fencing, in-order commit apply.MemTransport-- in-process stand-in for the network + the cold path (fixed leader, loginorchestration
GetRSCommitLSN → SyncRSCommitLSN → InternalLogin) + fault hooks(
set_up/force_subquorum). No production analog -- real servers + config play that role.create_memory_volume/make_memory_replica_set-- the thin adapter that wraps each replicabehind a
volume_handle; the only glue that reusesvolume(and therefore links HomeStore).HomeStore-free by construction: the model lib references no engine symbol -- its unit-test binary
links
sisl+ gtest withouthomestore::homestoreand still resolves (an undefined-symbol errorwould mean it touched the engine). Coroutines complete inline, so tests need no iomgr reactor.
Review guide
include/homeblks/{home_blocks.hpp, craft_types.hpp}volumelib/craft/craft_replica.hpp,lib/volume/volume.hpp(memory-mode ctor + nullablecraft_backend_),lib/craft/craft_api.cpplib/craft/memory/mem_craft_replica.{hpp,cpp}(start atread_range),mem_craft_cluster.{hpp,cpp}lib/craft/memory/mem_craft_volume.{hpp,cpp}lib/craft/memory/tests/Testing
15 model unit tests (login→write→keep_alive→read, overlay read above a committed hole, horizon clamp,
zero write & all-zero-data collapse, commit stall-at-gap / piggyback-on-write / piggyback-on-read, term
fencing incl.
keep_alive, misalignment rejection, replica-down & sub-quorum faults) + 3 end-to-endtests through the public
volume_handleAPI. Existingtest_volume/test_volume_io/homeblk_ublkstill build (legacy calls emit deprecation warnings, not errors).
Out of scope (seams left in place)
Full resync /
FetchDatafill loop,Empty/Missingverdicts, failed-sub-quorum-write resolution,reconfiguration (S10), skinny mode, logout/lease + stand-in client, journal reclaim, and crash/restart
recovery.
docs/craft/{api,rpcs,README}.mdare updated to the surface landed here.Notes for reviewers
lba_t/lba_count_tmoved to the shared HomeStore-freecraft_types.hpp(still reachableeverywhere via
home_blocks.hpp); the byte-based public API uses rawuint64_t.CraftReplDev(S1 stub) is otherwise untouched -- it just now includescraft_replica.hppfor the shared internal types (CraftPartitionState,JournalSlot), which movedoff the public surface.
conanfile.pyublkppversion bump.🤖 Generated with Claude Code