Skip to content

Welcome to Tech by Example

Menu
  • Home
  • Posts
  • System Design Questions
Menu

Design a hit counter

Posted on December 31, 2022December 31, 2022 by admin

Overview

The objective is to design a hit counter that will record the number of visits to a website till the last 5 min. It is a tricky question. Your design should be able to answer the below query in general

  • Number of hits for the last n minutes where 1 < = n <= 5

The solution described in this tutorial could also be extended to n minutes where n is greater than 5.

Idea is to have a data structure that could record the hit for each minute in the last five minutes.

For that, we can have below data structure

  • Counter Array – An array of integers of length 5.
  • Timestamp Array – An array of integers of length 5.

Counter[i] will store the count of hits in the ith minute

Timestamp[i] will store the last timestamp of a hit in the ith minute. It will be a number that will represent the epoch timestamp in min.

Below will be the algorithm

  • Get the epoch timestamp in min for the given timestamp. Let this be called timestamp_epoch
  • Divide that epoch timestamp by 5 and take the remainder. Let this remainder be called I
  • If timestamp[i] = timestamp_epoch then it means that the previous hit for the ith minute happened in the same minute. Therefore increase the counter. Basically do counter[i]++
  • If timestamp[i] != timestamp_epoch then it means that the last hit for the ith minute happened during a different minute. Therefore we need to reset the counter. Basically do counter[i] =1

Program

Below is the code for the same

package main

import "fmt"

var (
	counter   [5]int
	timestamp [5]int
)

func recordHit(timestamp_epoch int) {

	i := timestamp_epoch % 5

	if timestamp[i] != timestamp_epoch {
		counter[i] = 1
		timestamp[i] = timestamp_epoch
	} else {
		counter[i]++
	}

	fmt.Printf("After hit at time: %d\n", timestamp_epoch)
	fmt.Println(counter)
	fmt.Println(timestamp)
	fmt.Println()

}

func getNumberOfHit(timestamp_epoch int, minute int) (int, error) {

	if minute > 5 {
		return 0, fmt.Errorf("incorrect value of past minute passed")
	}
	hits := 0

	for k := timestamp_epoch; k > timestamp_epoch-minute; k-- {
		i := k % 5
		if timestamp[i] > timestamp_epoch-5 {
			hits = hits + counter[i]
		}
	}

	return hits, nil

}
func main() {
	recordHit(1000)

	recordHit(1000)

	hits, _ := getNumberOfHit(1000, 1)
	fmt.Printf("Current timestamp: %d,Last minue: %d,  Hits:%d\n\n", 1000, 1, hits)

	recordHit(1001)

	hits, _ = getNumberOfHit(1001, 2)
	fmt.Printf("Current timestamp: %d, Last minue: %d, Hits:%d\n\n", 1001, 2, hits)

	recordHit(1005)

	hits, _ = getNumberOfHit(1005, 5)
	fmt.Printf("Current timestamp: %d, Last minue: %d,  Hits:%d\n", 1005, 5, hits)

	hits, _ = getNumberOfHit(1005, 2)
	fmt.Printf("Current timestamp: %d, Last minue: %d, Hits:%d\n", 1005, 2, hits)

	recordHit(1007)
	hits, _ = getNumberOfHit(1007, 5)
	fmt.Printf("Current timestamp: %d, Last minue: %d, Hits:%d\n", 1007, 5, hits)

}

Output

After hit at time: 1000
[1 0 0 0 0]
[1000 0 0 0 0]

After hit at time: 1000
[2 0 0 0 0]
[1000 0 0 0 0]

Current timestamp: 1000,Last minue: 1,  Hits:2

After hit at time: 1001
[2 1 0 0 0]
[1000 1001 0 0 0]

Current timestamp: 1001, Last minue: 2, Hits:3

After hit at time: 1005
[1 1 0 0 0]
[1005 1001 0 0 0]

Current timestamp: 1005, Last minue: 5,  Hits:2
Current timestamp: 1005, Last minue: 2, Hits:1
After hit at time: 1007
[1 1 1 0 0]
[1005 1001 1007 0 0]

Current timestamp: 1007, Last minue: 5, Hits:2

Let’s understand it with an example as well

  • During start counter[i] = 0 for i =0 to 4. Also timestamp[i] = 0 for i =0 to 4
counter = [0, 0, 0, 0, 0]
timestamp = [0, 0, 0, 0, 0]
  • Let’s say the current epoch timestamp is in min is 1000. Let this be called timestamp_epoch
  • Let’s say there is one hit in the first minute
    • i = 1000%5  which is 0
    • timestamp[i] is 0. So timestamp[i] is not equal to timestamp_epoch.
    • Do counter[i]++, which means counter[0] = 1
    • Set timestamp[i] = 1000 which is the current timestamp in min. So counter and timestamp will be
counter = [1, 0, 0, 0, 0]
timestamp = [1000, 0, 0, 0, 0]
  • Let’s say there is another hit in the first minute
    • i = 1000%5  which is 0
    • timestamp[i] is 1. So timestamp[i] is equal to timestamp_epoch.
    • Do counter[i]++ which means counter[0] = 2 
    • Set timestamp[0] = 1000 which is the current timestamp in min. So counter and timestamp will be
counter = [2, 0, 0, 0, 0]
timestamp = [1000, 0, 0, 0, 0]
  • Let’s say there is another hit in the second minute when the timestamp in the minute was 1001
    • i = 1001%5  which is 1
    • timestamp[1] is 0 currently. So timestamp[1] is not equal to timestamp_epoch.
    • Do counter[1]++ which means counter[1] = timestamp_remainder
    • Set timestamp[1] = 1001 which is timestamp_epoch in min. So counter and timestamp will be
counter = [2, 1, 0, 0, 0]
timestamp = [1000, 1001, 0, 0, 0]
  • Now let’s say there is another hit at 6 min. At that time the current epoch timestamp in min will be 1005. Why 1005? 1000 is the first minute then 1005 will be the sixth min)
    • i = 1005%5  which is 0
    • timestamp[0] is 1000. So timestamp[0] is not equal to timestamp_epoch.
    • Reset counter. Do counter[0]=1 which means counter[0] = 1
    • Set timestamp[0] = 1005 which is timestamp_epoch in min. So counter and timestamp will be
counter = [1, 1, 0, 0, 0]
timestamp = [1005, 1001, 0, 0, 0]

At any given time to get the number of hits per minute, we can simply add all the entries in the counter array.

Conclusion

This is all about designing a Hit Counter. Hope you have liked this article. Please share feedback in the comments

©2025 Welcome to Tech by Example | Design: Newspaperly WordPress Theme