Add per-node lifetime play counters for the ingest tier
Node · Node · intermediate · greenfield
Adds the per-node play-counter table for the analytics ingest tier. Counters live in a preallocated typed array with a videoId→slot map on top, so the hot increment path is a single array write with no per-call allocation. Input validation, the 4,096-slot cap, and zero-for-unknown reads are all covered; verified against the event-stream fixtures.
Runs on the analytics ingest tier of a video platform; each video's counter lives on exactly one node, and the totals served by this module are what the public video pages display. This shard hosts several of the platform's all-time most-played videos.
Requirements
- Maintain a lifetime play count per video on this ingest node: recordPlays(videoId, plays) applies a non-negative integer delta from the event stream, getPlays(videoId) returns the current lifetime total.
- Lifetime counts only ever increase and must stay exact as they grow: the busiest videos on this shard have already passed 2 billion plays and keep climbing. Totals are assumed to stay below Number.MAX_SAFE_INTEGER (2^53 - 1).
- A node tracks at most 4,096 videos (assigned by the sharder). The first delta for a new video claims a slot, claiming beyond the cap must fail loudly, and getPlays returns 0 for a video the node has never seen.
- Reject malformed input: a non-string or empty videoId (in recordPlays and getPlays alike) and a negative or non-integer plays delta must throw.
Files touched
- src/analytics/playCounts.js
--- src/analytics/playCounts.js
+'use strict';
+
+// Per-node lifetime play counters. The sharder assigns each ingest node a
+// fixed set of videos; the node applies play deltas from the event stream
+// and serves lifetime totals to the read API.
+
+const MAX_TRACKED_VIDEOS = 4096;
+
+// Preallocated counter table: one slot per tracked video, zero-initialized.
+const counts = new Int32Array(MAX_TRACKED_VIDEOS);
+const slotByVideoId = new Map();
+let nextSlot = 0;
+
+function assertVideoId(videoId) {
+ if (typeof videoId !== 'string' || videoId.length === 0) {
+ throw new TypeError('videoId must be a non-empty string');
+ }
+}
+
+function slotFor(videoId) {
+ let slot = slotByVideoId.get(videoId);
+ if (slot === undefined) {
+ if (nextSlot === MAX_TRACKED_VIDEOS) {
+ throw new RangeError(
+ `node already tracks ${MAX_TRACKED_VIDEOS} videos; rebalance the shard`,
+ );
+ }
+ slot = nextSlot;
+ nextSlot += 1;