Implement cluster status tracker
Company: Anthropic
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's competence in data structures and algorithms for time-ordered state tracking, time-series indexing, conflict resolution (last-write-wins), memory-efficient storage, and concurrent system behavior under high update rates.
Part 1: Implement the cluster status tracker
Constraints
- 1 <= ttl <= 10^9
- 0 <= node_id, timestamp, t, cutoff <= 10^9
- 1 <= len(operations) <= 2 * 10^4
- Status strings are non-empty and never equal to 'OFFLINE'
- A node is counted in a summary at time t only if it has at least one update with timestamp <= t
Examples
Input: (5, [('update', 1, 'OK', 10), ('update', 2, 'WARN', 8), ('update', 1, 'ERROR', 7), ('getCurrent', 1), ('getAt', 1, 8), ('getClusterSummaryAt', 10)])
Expected Output: ['OK', 'ERROR', {'OK': 1, 'WARN': 1}]
Explanation: Node 1's newest update is at time 10 with status OK, but at time 8 its effective status is ERROR.
Input: (3, [('update', 1, 'OK', 5), ('update', 1, 'OK', 5), ('update', 2, 'WARN', 1), ('getAt', 2, 5), ('getClusterSummaryAt', 5)])
Expected Output: ['OFFLINE', {'OFFLINE': 1, 'OK': 1}]
Explanation: The duplicate update for node 1 changes nothing. Node 2 has not reported within TTL by time 5.
Hints
- For each node, keep timestamps sorted so you can binary-search the latest update not after t.
- During compaction, keeping the last update before the cutoff plus all updates at or after the cutoff is enough to answer future queries for times >= cutoff.
Part 2: Add efficient range queries
Constraints
- 1 <= ttl <= 10^5
- 0 <= minute <= 2 * 10^5
- 1 <= len(events) + len(queries) <= 2 * 10^5
- The number of distinct non-OFFLINE statuses is at most 20
- Status strings are non-empty and never equal to 'OFFLINE'
- For every query, 0 <= end_minute - k + 1 <= end_minute <= 2 * 10^5
Examples
Input: (2, [(1, 'OK', 1), (2, 'WARN', 2), (1, 'ERROR', 4)], [(4, 4)])
Expected Output: [[{'OK': 1}, {'OK': 1, 'WARN': 1}, {'OK': 1, 'WARN': 1}, {'ERROR': 1, 'WARN': 1}]]
Explanation: The query asks for summaries at minutes 1, 2, 3, and 4.
Input: (1, [(1, 'OK', 3), (1, 'WARN', 3), (2, 'OK', 1)], [(3, 3)])
Expected Output: [[{'OK': 1}, {'OK': 1}, {'OFFLINE': 1, 'WARN': 1}]]
Explanation: At minute 3, node 1 is WARN because later input wins at the same minute, and node 2 is OFFLINE.
Hints
- For one node, each update creates a time interval during which that status is active: from its minute until the earlier of TTL expiry or the next update.
- Difference arrays plus prefix sums let you build every minute's cluster summary once, then each query becomes a slice of the precomputed timeline.
Part 3: Schedule thread-safe sharded requests
Constraints
- 1 <= num_shards <= 10^4
- 0 <= node_id <= 10^9
- 0 <= len(requests) <= 2 * 10^4
- Each request mode is either 'R' or 'W'
- Each request may list the same node more than once, but a shard should only be locked once per request
Examples
Input: (4, [('R', [1, 5]), ('R', [2]), ('W', [6]), ('W', [1, 2])])
Expected Output: {'waves': 3, 'plan': [[[1], 0], [[2], 0], [[2], 1], [[1, 2], 2]]}
Explanation: The first two reads fit in wave 0. The writes must be separated because they conflict on touched shards.
Input: (3, [('W', [1]), ('W', [2]), ('R', [4])])
Expected Output: {'waves': 2, 'plan': [[[1], 0], [[2], 0], [[1], 1]]}
Explanation: The two writes touch different shards, so they can share wave 0. The final read touches shard 1 and must wait.
Hints
- Convert each request to the set of shards it touches first. The deadlock-free lock order is just the sorted list of those shards.
- For every wave, track which shards already have readers and which already have writers. Reads only need to avoid writers; writes need both sets to be disjoint.