skip to content

An in-memory store applies four submitted operations as one uninterleaved group; what does that promise, and what does it not?

level: juniorimportance: must knowfreq 68%

answer

  1. no one else gets in between
  2. queue and apply, not commit
  3. no isolation level, no snapshot
  4. no rollback; earlier steps stay applied

basics

~10 s

It promises only that no other caller's operation is applied between the four. It is not a database transaction: there is no rollback, so when the third step fails, the first two stay applied.

solid answer

~40 s

The construct assembles several operations and applies them back to back as one unit, so no other caller's operation lands in the middle. That non-interleaving is the entire guarantee. There is no isolation level to pick, no snapshot for the reads inside the group, no save point and, above all, no rollback: if a step fails while the group is being applied, the steps before it stay applied, and on most stores that offer this construct the steps after it are applied too. The caller gets one result per step and owns whatever repair the half-applied state needs. Think `queue and apply`, not `commit and undo` — and check the store you are on, because some stores in this class offer no grouping construct at all.

go deeper

for a junior

Remember the one promise — no other caller's operation runs between the grouped steps — and the one absence: nothing is undone when a step fails.

for a middle

Explain why this is not a database transaction: no rollback, no isolation level, no snapshot for the reads inside it. Then say exactly what is stored after a step fails mid-apply.

for a senior

Show that you read the per-step results and design the repair, because a half-applied group is a normal outcome rather than an exception. Say what happens when the caller that owed the repair has died.

for a principal

Decide which invariants may rest on this tier at all, given that it offers non-interleaving and nothing else, and state where the authority for the rest of them lives.

## The one thing a group buys Several stores in this class let a caller hand the server more than one operation to be applied as a single unit: the operations are assembled, the caller marks the boundary, and the store applies them back to back. While that unit is being applied, **no other caller's operation is applied in between**. That non-interleaving property is the whole of what the construct promises, and it is worth saying out loud, because nearly everything else people expect from it is absent. Where the guarantee comes from is the store's own business rather than yours. Some stores run one operation to completion before starting the next, so applying a group is simply a longer run to completion. Others run several worker threads and lock the entry being operated on for the duration of an operation, reaching the same per-operation guarantee by a different route and extending it across the group. A caller on either kind of store is handed the same promise. ## What it is not The word that attaches itself to this construct in conversation is *transaction*, and that word imports expectations from relational databases that simply do not hold at this tier. | Expected from a database transaction | What an operation group actually gives | |---|---| | **All-or-nothing** — a rollback undoes the statements already run | Nothing is undone; a failing step leaves its predecessors applied | | **A chosen isolation level** | Nothing to choose; non-interleaving is all the isolation there is | | **A snapshot** — every read inside sees one point in time | Each step reads the entry as it stands when that step is applied | | **A save point** to unwind to | No markers, no partial undo, no nesting | | **One verdict** for the whole unit | One result per step, and the caller reads the list | The honest summary is **queue and apply, not commit and undo**. There is no commit point at which the store decides whether the work counts. By the time you learn that the third step failed, the first two are already visible to every other caller. ## The two moments something can go wrong A group has two distinct failure moments, and they leave very different states behind. It can be **refused while it is being assembled** — on stores that check the shape of each operation as it is queued, one malformed step can cause the whole group to be refused, in which case nothing was applied and the keyspace is untouched. Or it can be **accepted and then error while it is being applied**, when a step turns out not to fit the value that is actually stored under its key. In that case the earlier steps stay applied, and on most stores offering this construct the later steps are applied as well rather than skipped. Those two outcomes look alike in a diagram and nothing alike in code. ## What varies across stores - **Whether the construct exists at all.** Some stores in this class offer no grouping construct whatsoever; their only multi-step atomicity comes from a submitted program, from a version token presented on write, or from restructuring the data so the change is a single operation. A design that assumes a group is not portable across this class. - **How much is checked at assembly time.** Some stores validate each operation as it is queued; others discover the problem only while applying. - **Whether the steps after a failing one still run.** Treat *they do* as the default and confirm it for the store you are on. - **Whether the entries must share a node.** Where the keyspace is split across nodes, a unit touching several entries is only possible when those entries are co-located; the placement rules themselves are a separate subject. - **What "applied" means for survival.** Applying changed memory on one node. Whether the effect survives a restart, or had reached a replica before the node was lost, is a property of the tier's durability and replication posture, not of the group. One further distinction is worth nailing down because it is confused constantly: sending many operations without waiting for each reply is a **round-trip optimisation**. It makes a loop of calls fast; it promises nothing at all about whether another caller's operation lands between two of them. Grouping and not-waiting-for-replies are different mechanisms that happen to look similar from the client's side. ## Designing with it 1. Ask first what would actually break if another caller's operation landed between your steps. If the answer is *nothing*, you do not need the construct. 2. Order the steps so that any prefix of them leaves a state the rest of the system can live with — the step that makes the work visible to readers goes last. 3. Read the per-step results. One acknowledgement for the group is not evidence that every step applied. 4. Write the repair for a half-applied group before you ship the group, make it idempotent, and make sure something other than the submitting caller can run it. 5. If what you genuinely need is all-or-nothing across several entries, this tier is not the place that invariant can be enforced; enforce it where rollback exists and let this tier hold the fast copy.

  • Do the reads inside a group see a consistent snapshot of the keyspace?
    No. Each read inside the group returns the entry as it stands at the moment that step is applied; nothing was frozen when the group was assembled, and a value the caller read before submitting may already be stale. If the group's correctness depends on an entry not having changed, you need a mechanism that declares the entries the group depends on and abandons the group when one of them changes — a separate construct, and not something the group gives you by itself.
  • Once a group has been applied, is its effect durable?
    Applying is not persisting. Whether the effect survives a restart depends on the tier's durability posture, and on a replicated tier an effect applied on the primary may not have reached a replica before the primary is lost. The unit is about what other callers see while it is applied, not about what survives the node.

Four errands run back to back by one assistant: nobody else gets their attention in between, but if the third shop is closed, the first two errands are still done and nothing un-buys them.

saying these in an interview costs you the question

  • Calls the group a transaction and expects a rollback on failure.
  • Thinks a failing step undoes the steps already applied.
  • Believes the group selects an isolation level for its reads.
  • Assumes every in-memory store offers a grouping construct.
  • Thinks sending operations without waiting for replies stops other callers interleaving.