Beacon Activity Window
Problem
Field beacons report observations with explicit timestamps. Design BeaconActivityWindow to retain those observations and answer which beacons were active during a configurable window ending at any requested time. Multiple threads may share one instance.
Requirements
- Recorded history. The logical observation history contains exactly the valid
(beaconId, observedAtSecond)pairs supplied to completedrecordPulsecalls. - Historical queries. Query timestamps may move forward or backward, and an earlier query must not alter the result of any later query.
- Exact activity.
isActivereturnstrueexactly when the named beacon has an observation in the inclusive interval[asOfSecond - windowSeconds + 1, asOfSecond]. - Distinct total.
activeBeaconCountreturns the number of distinct beacon IDs that satisfy Exact activity for itsasOfSecond. - Atomic shared access. Every public call is linearizable when threads share one instance.
API
| Signature | Returns | Behavior |
|---|---|---|
BeaconActivityWindow(windowSeconds: integer) | New BeaconActivityWindow | Creates an empty history and fixes the window size. |
recordPulse(beaconId: string, observedAtSecond: integer) | void | Adds the observation to the logical history. |
isActive(beaconId: string, asOfSecond: integer) | boolean | Reports whether the beacon has an observation in the activity interval. |
activeBeaconCount(asOfSecond: integer) | integer | Reports the number of distinct active beacons. |
Examples
For a window size of 3:
| Step | Operation | Result |
|---|---|---|
| 1 | isActive("alpha", 5) | false |
| 2 | recordPulse("alpha", 5) | No return value |
| 3 | isActive("alpha", 7) | true |
| 4 | activeBeaconCount(7) | 1 |
| 5 | isActive("alpha", 8) | false |
Constraints
1 <= windowSeconds <= 120beaconIdmatches[a-z][a-z0-9-]{0,19}- Each testcase uses at most
100distinct beacon IDs. 0 <= observedAtSecond, asOfSecond <= 10_000- Each testcase has at most
200public-method calls and12threads. - The same
(beaconId, observedAtSecond)pair is not recorded twice. - All supplied inputs are valid and non-null.
- Timestamps use signed 64-bit integer bindings in Java and C++, and Python integers. Counts fit signed 32-bit integers.
Notes
All testcase threads share one object. Calls retain their listed order within one thread. Calls from different threads may interleave in any order consistent with real-time precedence.
Linearizable means that each call takes effect at one instant between its invocation and response. A query that overlaps a recordPulse call may include or exclude that observation according to either valid ordering. A query invoked after that record returns must include it when its timestamp lies in the query interval.
Public operations have no domain waiting condition. Cancellation, shutdown, fairness, user-visible timeouts, and wait-free progress are outside the contract.