Function: mayberotate in write-ahead-log/wal.py

Date: 2026-05-29

Time: 08:25

mayberotate — Conditional WAL File Rotation

Purpose

mayberotate is a size-based rotation guard. It checks whether the current WAL segment file has grown past the configured size limit (maxfile_size, default 10 MB) and, if so, triggers rotation to a new file. This prevents any single WAL file from growing unbounded, which matters for two reasons: it bounds the cost of replaying a single segment during crash recovery, and it lets truncate() delete entire files worth of old records rather than rewriting one monolithic file.

Contract

Parameters

None. It reads instance state only: self.fd (the open file handle) and self.maxfilesize (the rotation threshold).

Return Value

None. The method communicates entirely through side effects on instance state.

Algorithm

1. Guard on self.fd: If the file descriptor is None (e.g., after close() or during truncate()), do nothing. This is a defensive check — in normal operation fd is always set when this is called.

2. Check file position: self._fd.tell() returns the current write offset — effectively the file size since the file is opened in append mode ("ab").

3. Compare against threshold: If the position is at or above maxfilesize, delegate to self.rotate().

That's it — three lines doing one thing.

Side Effects

When rotation triggers:

When rotation does not trigger: no side effects at all.

Error Handling

None explicit. If tell() fails (e.g., on a closed fd), the exception propagates to the caller. If rotate() fails to create the new file (permissions, disk full), that also propagates uncaught. The method trusts that fd is in a valid state when called.

Usage Patterns

Called as the final step in every write path — after dosync(), never before:


# In append():
self._fd.write(data)
self._do_sync()
self._maybe_rotate()    # rotate AFTER the write is durable

# Same pattern in append_batch() and checkpoint()

The ordering is deliberate: the write and sync happen to the current file first, so the data is durable before rotation closes that file. If rotation were called before sync, the fsync inside rotate() would still cover it (since rotate flushes before closing), but the current ordering makes the intent clearer and keeps dosync's batch-counting logic coherent.

Caller obligation: callers must hold self._lock before calling this method. There is no internal locking.

Dependencies

Assumptions Not Enforced by the Type System

1. A single write can exceed maxfilesize. If a batch is larger than the limit, maybe_rotate will rotate *after* that write, meaning one segment can temporarily exceed the cap. The check is >=, not a pre-write check, so this is by design — it's a soft limit.

2. _fd opened in append mode. tell() only equals file size if the file was opened with "ab". If someone changed the open mode, tell() could report a misleading position.

3. Called under lock. Nothing prevents a direct call without the lock — the method doesn't acquire it and doesn't assert it's held.

Beliefs