skip to content

Rotating a 10^9-entry memory-mapped log by k: is an O(1)-space in-place rotation the right call?

level: principalimportance: should knowfreq 35%

answer

  1. ask who actually observes the rotation
  2. an offset can rotate without moving bytes
  3. constant extra space is not free
  4. every page dirtied means writeback pressure
  5. a crash mid-rotation leaves neither order

basics

~20 s

Often not. The cheapest rotation of a huge log is logical: keep a base offset and index modulo n, moving nothing. A physical in-place rotation saves memory but rewrites every page and is not crash-safe.

solid answer

~50 s

First challenge the requirement. If only readers need rotated order, store a base offset and map index `i` to `(i + base) mod n` — one integer written, nothing moved. Physical rotation is justified only when the on-disk order itself is the contract for an outside consumer. Then the choice is not asymptotic: an in-place three-reversal costs O(1) extra space but dirties every page of 10^9 entries, and after a crash leaves a file that is neither the old order nor the new one. Writing a rotated copy and renaming costs a second full copy of storage but is atomic and trivially retried. Decide by which failure you can afford: if storage headroom is the constraint that binds, rotate in place and persist a phase marker so a restart resumes; if crash consistency is, pay for the copy.

go deeper

for a junior

Know that rotating in place avoids allocating a second array, and that the same operation on a very large file is not the same problem as on a small array in memory.

for a middle

Explain the concrete costs on both sides — a full extra copy versus every page rewritten — and state that a three-reversal rotation is linear time with constant extra space.

for a senior

Demonstrate the crash-safety reasoning: a rename is atomic, an in-place rewrite is not, and a resumable in-place rotation needs a persisted phase marker.

for a principal

Own the reframing that the cheapest rotation may move no data at all, and defend the chosen option against the constraint that actually binds — storage headroom, latency during writeback, or recovery effort.

## Start by attacking the requirement "Rotate the log by k" is almost never a requirement in itself. It is usually a consequence of something else: a retention window moved, a shard's start boundary shifted, a consumer that wants to begin reading at a different entry. So the first question is who observes the rotation. If the answer is "our own readers", there is a rotation that costs nothing: store a base offset alongside the data and map a logical index `i` to the physical index `(i + base) mod n`. Rotating by k becomes `base = (base + k) mod n` — a single write of one integer, O(1) time, O(1) space, no data moved, no pages touched, and atomic by construction. On 10^9 entries this is not an optimisation, it is a different order of magnitude of cost. A senior candidate reaches for the three-reversal trick; a lead asks whether any bytes need to move. The indirection is not free forever: every reader now pays a modulo on access, sequential scans wrap once in the middle, and the offset becomes a piece of state that has to be replicated, versioned and reasoned about at recovery. Those are real costs, and they are the reason someone will eventually want the physical order normalised anyway — but on a schedule you choose, not in the middle of an incident. ## When bytes genuinely must move Physical rotation earns its keep when the raw byte order is the contract: an external consumer memory-maps the file and reads it front to back without knowing about your offset, a checksum or index is computed over the physical layout, or the file is handed to a system you do not control. Then the choice is between two real strategies. | | in-place (three reversals) | copy rotated, then rename | |---|---|---| | extra space | O(1) | a second full copy of the file | | passes over data | three, all sequential | one sequential read plus one write | | pages dirtied | every page, twice | every page of the new file once | | crash behaviour | file left in a partial state | old file intact until the rename | | retry | needs a persisted phase marker | just start over | | readers during the work | see torn, inconsistent order | see the old order until the swap | The in-place route's O(1) extra space is a genuine advantage only when storage headroom or resident memory is the binding constraint — a fleet where nodes are provisioned near capacity, or a device where a second copy of the file simply does not fit. That constraint is real and common enough to be the reason the technique is worth knowing. What it costs is everything in the bottom half of that table. Rewriting every entry of a memory-mapped 10^9-element region dirties every page, and the resulting writeback pressure competes with whatever else the node is serving; p99 latency for unrelated work moves while the rotation runs. Worse, there is no moment at which the file is consistent: a crash between the second and third reversal leaves data that matches neither the old layout nor the new one, and nothing in the file says which phase was reached. The copy-and-rename route buys atomicity from the filesystem for the price of storage. ## Making the in-place route survivable If headroom forces in place, do not ship the bare three lines. Persist a small durable header recording k and which of the three reversals has completed, updating it between phases; on restart, resume from the recorded phase. This works because each phase is a whole range reversal with known boundaries — but note that a crash *inside* a phase leaves that range partially reversed, so either the phase marker must be finer-grained or the restart must be able to re-derive the range's state. That awkwardness is itself an argument: the recovery design costs more engineering than the copy would have cost in disk. Also resist the temptation to reach for the cleverest rotation available. A cycle-based rotation performs half the writes, but its correctness rests on a cycle-counting argument, and this is code someone will read at three in the morning while the log is half-rotated. Three calls to a reversal primitive is what you want in a runbook. ## How to present the decision Frame it as failure modes, not cleverness. "In place if storage headroom is the constraint we cannot move and we accept building resume logic; copy-and-rename if we want the rotation to be atomic and retryable and we can afford the second copy; neither if we can push the rotation into an offset and touch no bytes at all." Then say which one you would pick given the constraint that actually binds today, and what measurement would change your mind — free storage on the tightest node, the writeback impact on p99 during a rehearsal, and how often this rotation is expected to happen at all. A rotation performed once a year and a rotation performed hourly deserve different answers.

  • What would push you toward the in-place rotation despite its risks?
    A hard storage or memory ceiling: nodes provisioned with no room for a second copy of the file, where the copy route simply cannot run. Also a case where the file's identity must be preserved because other processes hold it open, or where only a small window of the log is being rotated so the dirtied-page cost is bounded. Those are constraints, not preferences — say which one applies.
  • How would you make an in-place rotation of a huge file restartable?
    Persist a durable header with k and the completed phase, and update it between the three reversals so a restart resumes at the right one. The gap is a crash inside a phase, which leaves a partially reversed range; either checkpoint progress within the range or make each phase idempotent by recording its swap frontier. If that design starts to look expensive, that is the signal to pay for the copy instead.
  • How do you argue this to a team that wants the three-line version merged today?
    Do not argue about elegance; price the failure. Show what the file looks like after a crash between phases, ask who pages in to fix it, and compare that to the cost of the extra storage. Then offer the offset-based rotation as the option that avoids both, and let the team choose against a stated constraint rather than against your taste.

Changing where the year starts on a calendar is cheaper than reprinting every page — until someone else is reading your printed pages and cannot be told about the new starting month.

saying these in an interview costs you the question

  • Insists O(1) extra space is always the better engineering choice
  • Never considers rotating an index instead of the data
  • Ignores crash safety when rewriting a file in place
  • Treats writes to a huge mapped file as free like in-memory writes
  • Picks the cycle-based rotation because it writes less
  • Cannot name the constraint that would flip the decision

context