Preserve committed entities across batches without rewriting history - #1263
Conversation
Instead of dropping the whole InMemoryStore after each batch write, keep the latest entity changes (up to 50k per table) so the next batch can read them without hitting the database. Only per-batch index state and the rollback history are reset. - Inline the former standalone clear into writeBatch (partial reset) and prepareRollbackDiff (full reset) - Track commitedCheckpointId on the InMemoryStore - Filter prevEntityChanges and batch changes by commitedCheckpointId instead of the loaded-from-db checkpoint, so already committed entities carried across batches don't re-emit history https://claude.ai/code/session_01JRHFPTtYobx3WjahffvE1y
Sum entity counts across all tables and keep (or drop) the latest changes for the whole InMemoryStore at once, rather than per-table. https://claude.ai/code/session_01JRHFPTtYobx3WjahffvE1y
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughStore now tracks committedCheckpointId (initialized from Internal.initialCheckpointId), uses it to filter and retain entity changes across batch writes, adds a table helper to keep latest changes, and threads the committed checkpoint through rollback and in-memory write paths. ChangesIncremental Entity Update Tracking
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Initialize the store's commitedCheckpointId from a dedicated initialCheckpointId constant instead of reusing loadedFromDbCheckpointId. https://claude.ai/code/session_01JRHFPTtYobx3WjahffvE1y
The table is reset with a fresh prevEntityChanges right after, so we can append the latest changes onto the existing array instead of copying it. https://claude.ai/code/session_01JRHFPTtYobx3WjahffvE1y
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/envio/src/InMemoryStore.res (1)
44-44:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winTypo:
commitedCheckpointIdshould becommittedCheckpointId."Committed" has double 't'. Since this is a new field being introduced, fixing the spelling now avoids propagating the typo across the codebase.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/envio/src/InMemoryStore.res` at line 44, Rename the misspelled mutable field commitedCheckpointId to committedCheckpointId in InMemoryStore.res and update every reference to that field (constructors, record literals, pattern matches, getters/setters, and any modules accessing Internal.checkpointId) to use the new spelling; ensure compilation by running the build/tests and fix any remaining identifier usages or imports that referenced commitedCheckpointId.
🧹 Nitpick comments (1)
packages/envio/src/InMemoryStore.res (1)
169-175: 💤 Low valueConsider using
reduceinstead of ref for accumulation.This is more idiomatic ReScript:
♻️ Suggested refactor
- let totalLatestChanges = ref(0) - persistence.allEntities->Belt.Array.forEach(entityConfig => { - totalLatestChanges := - totalLatestChanges.contents + - (inMemoryStore->getInMemTable(~entityConfig)).latestEntityChangeById->Utils.Dict.size - }) - let keepLatestChanges = totalLatestChanges.contents < keepLatestChangesLimit + let totalLatestChanges = persistence.allEntities->Belt.Array.reduce(0, (acc, entityConfig) => { + acc + (inMemoryStore->getInMemTable(~entityConfig)).latestEntityChangeById->Utils.Dict.size + }) + let keepLatestChanges = totalLatestChanges < keepLatestChangesLimit🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/envio/src/InMemoryStore.res` around lines 169 - 175, The accumulation using a mutable ref (totalLatestChanges) is non-idiomatic — replace the ref loop with a pure fold: use persistence.allEntities->Belt.Array.reduce to sum each entity's inMemoryStore->getInMemTable(~entityConfig).latestEntityChangeById->Utils.Dict.size and then compare the resulting total to keepLatestChangesLimit to set keepLatestChanges; remove totalLatestChanges ref and the forEach to keep code functional and clearer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/envio/src/InMemoryStore.res`:
- Line 44: Rename the misspelled mutable field commitedCheckpointId to
committedCheckpointId in InMemoryStore.res and update every reference to that
field (constructors, record literals, pattern matches, getters/setters, and any
modules accessing Internal.checkpointId) to use the new spelling; ensure
compilation by running the build/tests and fix any remaining identifier usages
or imports that referenced commitedCheckpointId.
---
Nitpick comments:
In `@packages/envio/src/InMemoryStore.res`:
- Around line 169-175: The accumulation using a mutable ref (totalLatestChanges)
is non-idiomatic — replace the ref loop with a pure fold: use
persistence.allEntities->Belt.Array.reduce to sum each entity's
inMemoryStore->getInMemTable(~entityConfig).latestEntityChangeById->Utils.Dict.size
and then compare the resulting total to keepLatestChangesLimit to set
keepLatestChanges; remove totalLatestChanges ref and the forEach to keep code
functional and clearer.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 124767f1-b0f4-4af3-8d03-a03f96dc2a5a
📒 Files selected for processing (1)
packages/envio/src/InMemoryStore.res
- Rename commitedCheckpointId -> committedCheckpointId to match the existing spelling used in ChainManager/GlobalState - Replace the ref accumulator with Belt.Array.reduce when summing the store's latest changes https://claude.ai/code/session_01JRHFPTtYobx3WjahffvE1y
ref-based accumulation is the idiomatic style in this codebase. https://claude.ai/code/session_01JRHFPTtYobx3WjahffvE1y
Summary
This change ensures that entities committed in previous batches are preserved in the in-memory store and can be read in subsequent batches without hitting the database, while maintaining correct history tracking.
Key Changes
commitedCheckpointIdfield to track the last committed checkpoint, replacing the previous approach of checking againstloadedFromDbCheckpointIdlatestEntityChangeByIdfor entities below a size threshold (50,000 entities)commitedCheckpointIdto the last checkpoint in the batchresetButKeepLatestChanges()to drop per-batch state while preserving committed entitiesset()to acceptcommitedCheckpointIdparameter for accurate change trackingcommitedCheckpointIdinstead ofloadedFromDbCheckpointId, ensuring only uncommitted changes are written to the databaseImplementation Details
commitedCheckpointIdacts as a watermark to distinguish between committed changes (which should be preserved) and in-batch changes (which should be written)https://claude.ai/code/session_01JRHFPTtYobx3WjahffvE1y
Summary by CodeRabbit
New Features
Bug Fixes
Tests