Katkat

Execute TTL Cache Operations with Fetch-on-Miss

TubiSoftware Engineer · Technical Screen

Last updated

Implement a deterministic TTL cache simulator with put, get, delete, size, and fetch-on-miss operations. Preserve expired records until deletion or replacement, model loader success and failure explicitly, and validate timestamped JSON-compatible inputs.

Execute TTL Cache Operations with Fetch-on-Miss

Implement a pure simulator for a TTL cache. The simulator includes put, get, delete, size, and a deterministic adapter for a loader-based fetch operation.

def execute_ttl_cache(operations: list[list[object]]) -> list[list[object]]:
 ...

Operation formats are:

  • ["put", time_ms, key, value, ttl_ms]
  • ["get", time_ms, key]
  • ["delete", time_ms, key]
  • ["size", time_ms]
  • ["fetch", time_ms, key, ttl_ms, loader_status, loader_payload]

Keys are strings and cached values are integers. Times are nonnegative integers in nondecreasing order. A positive TTL expires at put_time + ttl_ms, and the key is invalid at that exact time. TTL zero means no expiration.

The exact result for each operation is:

  • put: ["ok"]
  • get: ["ok", value] for a valid entry, otherwise ["ok", null]
  • delete: ["ok", boolean], where the boolean is true when a stored key existed, even if it was expired
  • size: ["ok", count], including stored expired entries
  • fetch: return a valid cached value without consulting the supplied loader fields; on a miss or expired entry, loader_status is either "ok" or "error". For "ok", replace the entry with loader_payload and the supplied TTL, then return ["ok", value]. For "error", do not modify the cache and return ["error", reason].

Expired entries remain stored until delete or replacement. This makes the specified size behavior observable. The fetch operation represents the outcome of calling a loader rather than accepting a function object, so every input remains JSON-marshalable and deterministic.

Constraints and Error Rules

  • 0 <= len(operations) <= 200000
  • ttl_ms is nonnegative.
  • loader_payload is an integer when loader_status is "ok" and a string reason when it is "error".
  • Malformed operations, decreasing timestamps, invalid types, or unknown names must raise ValueError.
  • Return values are compared exactly.

Example

Input:
[
 ["put", 0, "u", 1, 5],
 ["get", 4, "u"],
 ["get", 5, "u"],
 ["size", 5],
 ["fetch", 6, "u", 10, "ok", 2],
 ["fetch", 7, "v", 0, "error", "db_down"],
 ["size", 7],
 ["delete", 8, "u"],
 ["size", 8]
]

Output:
[
 ["ok"],
 ["ok", 1],
 ["ok", null],
 ["ok", 1],
 ["ok", 2],
 ["error", "db_down"],
 ["ok", 1],
 ["ok", true],
 ["ok", 0]
]

Hints

  • Keep the stored record distinct from the result of checking whether it is currently valid.
  • Fetch has a check phase and, only on a miss, a loader-outcome phase.
  • Replacing an expired key should update all of its metadata.