Skip to content

CraftReplDev write path#165

Open
sbinmalek wants to merge 4 commits into
eBay:dev/v6.xfrom
sbinmalek:craft-write-path
Open

CraftReplDev write path#165
sbinmalek wants to merge 4 commits into
eBay:dev/v6.xfrom
sbinmalek:craft-write-path

Conversation

@sbinmalek

@sbinmalek sbinmalek commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Implements the client-facing write path for CraftReplDev (S2 of the CRAFT epic). Builds on the S1 foundation; the next subtask (S3) will add read, commit, and keep-alive.

  • STALE_TERM error — new volume_error enum value returned when a write arrives with a term older than state_.term; callers can branch on it to trigger re-login
  • HomeStoreCraftJournalBackend stub — production backend skeleton in craft_repl_dev.cpp; all three methods (write_slot, read_slot, truncate_to) log a warning and return not_supported pending HomeStore CRAFT journal APIs
  • CraftReplDev::write() — real implementation: term check → missing-set + last_append_lsn update (under missing_mu_) → co_await journal_->write_slot(); out-of-order arrivals are tracked in missing_lsns_ and filled in on subsequent writes
  • Unit tests — MockCraftJournalBackend (in-memory std::map-backed) + CraftWriteTest fixture with three cases: in-order writes, out-of-order gap tracking, and STALE_TERM rejection

Test plan

  • CraftWriteTest/InOrderWrites — lsns 0,1,2 sequential; missing set stays empty; last_append_lsn = 2
  • CraftWriteTest/OutOfOrderWrites — jump to lsn=4 creates {1,2,3} in missing set; filling in clears it
  • CraftWriteTest/TermRejection — term=1 against state_.term=0 → STALE_TERM; journal untouched
  • All existing volume tests still pass

sbinmalek and others added 3 commits June 23, 2026 20:39
Adds STALE_TERM to volume_error so CRAFT write/read rejections are
branchable by callers (triggers client re-login). Introduces
HomeStoreCraftJournalBackend as the production CraftJournalBackend
implementation and make_homestore_journal_backend() as its factory;
each journal method is stubbed pending HomeStore CRAFT journal APIs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Term check rejects stale-session IOs with STALE_TERM. Missing set is
updated under lock before the journal write so gaps are conservatively
tracked even on write failure. last_append_lsn advances to max of
current and incoming LSN. Journal append is zero-copy; LBA index is
not touched (that is commit()'s job).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add missing_count() / is_missing() const observability methods;
  mark missing_mu_ mutable so const methods can acquire the lock.
- Give JournalSlot::data a default member initializer ({}) so partial
  aggregate initializers don't trigger -Wmissing-field-initializers.
- Wire craft/tests/ into CMake and add test_craft_write:
  MockCraftJournalBackend (in-memory, map-backed), CraftWriteTest
  fixture, and three tests covering in-order writes, out-of-order
  gap tracking, and STALE_TERM rejection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the client-facing write path for CraftReplDev (CRAFT epic S2), introducing a new volume_error::STALE_TERM for session/term rejection and adding initial unit tests plus a stub production journal backend factory.

Changes:

  • Add CraftReplDev::write() implementation with term checking and missing-LSN tracking.
  • Introduce HomeStoreCraftJournalBackend stub + make_homestore_journal_backend() factory for production wiring.
  • Add CraftWriteTest with an in-memory journal backend and CMake integration for craft tests.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/lib/craft/tests/test_craft_write.cpp Adds unit tests and an in-memory MockCraftJournalBackend to validate write ordering and term rejection behavior.
src/lib/craft/tests/CMakeLists.txt Adds test_craft_write target and registers it with CTest.
src/lib/craft/craft_repl_dev.hpp Adds missing-set observability helpers, makes the mutex mutable, and declares the HomeStore journal backend factory.
src/lib/craft/craft_repl_dev.cpp Adds the production backend stub + factory and replaces the write() stub with a real implementation.
src/lib/craft/CMakeLists.txt Adds tests/ subdirectory to the craft build.
src/include/homeblks/home_blocks.hpp Extends volume_error with STALE_TERM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +85 to +107
// 2. Update missing set and last_append_lsn under lock.
// Done before the journal write so the missing set is always conservative:
// a failed write leaves the LSN in the set (correctly marked absent).
{
std::lock_guard lock{missing_mu_};
// Any LSNs between the old last_append and this one are gaps.
for (int64_t gap = state_.last_append_lsn + 1; gap < lsn; ++gap) {
missing_lsns_.insert(gap);
}
// This slot is being filled.
missing_lsns_.erase(lsn);
state_.last_append_lsn = std::max(state_.last_append_lsn, lsn);
}

// 3. Journal append — zero-copy; data buffer is not copied on the hot path.
auto res = co_await journal_->write_slot(lsn, lba, len, std::move(data));
if (!res) {
LOGE("write_slot failed lsn={} lba={} len={}: {}", lsn, lba, len, res.error().message());
co_return std::unexpected(res.error());
}

LOGT("write ok lsn={} lba={} len={}", lsn, lba, len);
co_return homestore::ok();
Comment on lines +79 to +83
// 1. Term check — old-session client; must re-login.
if (term != state_.term) {
LOGW("write rejected: stale term want={} got={} lsn={}", state_.term, term, lsn);
co_return std::unexpected(make_error_condition(volume_error::STALE_TERM));
}
Comment thread src/include/homeblks/home_blocks.hpp Outdated
Comment on lines +69 to +71
ENUM(volume_error, uint16_t, UNKNOWN_VOLUME = 1, CRC_MISMATCH, INDEX_ERROR, INTERNAL_ERROR, OFFLINE,
STALE_TERM
);
// Term rejection: write with term != state_.term returns STALE_TERM.
// Journal must not be touched.
TEST_F(CraftWriteTest, TermRejection) {
// state_.term starts at 0; term=1 is stale.
@sbinmalek sbinmalek marked this pull request as ready for review June 24, 2026 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants