-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathincoming_requests.cpp
More file actions
149 lines (110 loc) · 3.61 KB
/
incoming_requests.cpp
File metadata and controls
149 lines (110 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <bits/stdc++.h>
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
/*
Implement a thread-safe data structure that tracks incoming requests grouped by IP over a time window.
Add support for grouping by other attributes (e.g., BrowserAgent).
-----
Solution
Goal ->
1. Track incoming requests grouped by IP
2. Support a sliding time window
3. Ensure thread-safe updates and reads
4. Allow easy extension for grouping by other attributes
-----
Clarifications / Assumptions ->
1. Each request has a timestamp (epoch seconds)
2. Time window is sliding (last W seconds)
3. Exact counts are required (no approximation)
4. Data structure is in-memory
5. Starvation is acceptable (simple locking)
-----
Invariants ->
1. Only requests with timestamp >= (now - WINDOW) are counted
2. Requests are immutable events
3. For each IP, timestamps are stored in increasing order
4. Memory usage is bounded by evicting old timestamps
5. All shared state is protected by a mutex
-----
Approach ->
1. Use an unordered_map to group requests by IP
2. For each IP, maintain a queue (deque) of timestamps
3. On every insert or read:
a. Remove timestamps older than (now - WINDOW)
4. Protect the entire structure using a single mutex
-----
Scenarios ->
1. Multiple threads recording requests for same IP
2. Multiple threads querying counts concurrently
3. Requests arriving out of order (handled by timestamp checks)
4. IP stops sending requests -> entry removed automatically
*/
using namespace std;
#define WINDOW 5 // sliding window size in seconds
// Request object (immutable)
struct Request {
uint64_t timestamp;
string ip;
string agent; // optional grouping attribute (unused for now)
};
class TrackRequests {
// Map -> IP -> timestamps of requests
unordered_map<string, deque<uint64_t>> requests;
mutex mtx;
// Remove expired timestamps for a given IP
void cleanup(const string& ip, uint64_t now) {
auto& q = requests[ip];
while (!q.empty() && q.front() <= now - WINDOW) {
q.pop_front();
}
// Remove IP entry if no requests remain
if (q.empty()) {
requests.erase(ip);
}
}
public:
// Called when a request arrives
void recordRequest(const Request& r) {
unique_lock<mutex> lock(mtx);
requests[r.ip].push_back(r.timestamp);
cleanup(r.ip, r.timestamp);
}
// Called to query request count for an IP
int getRequestCount(const string& ip, uint64_t now) {
unique_lock<mutex> lock(mtx);
if (requests.find(ip) == requests.end()) {
return 0;
}
cleanup(ip, now);
return requests[ip].size();
}
};
// Simulated request generator
void Client(TrackRequests& t, string ip, int delay) {
this_thread::sleep_for(chrono::milliseconds(delay));
t.recordRequest({static_cast<uint64_t>(time(nullptr)), ip, ""});
cout << "Request from IP " << ip << endl;
}
// Simulated reader
void Monitor(TrackRequests& t, string ip) {
this_thread::sleep_for(chrono::milliseconds(200));
int count = t.getRequestCount(ip, time(nullptr));
cout << "Count for IP " << ip << " = " << count << endl;
}
int main() {
TrackRequests tracker;
thread c1(Client, ref(tracker), "1.1.1.1", 10);
thread c2(Client, ref(tracker), "1.1.1.1", 20);
thread c3(Client, ref(tracker), "2.2.2.2", 30);
thread c4(Client, ref(tracker), "2.2.2.2", 40);
thread m1(Monitor, ref(tracker), "1.1.1.1");
thread m2(Monitor, ref(tracker), "2.2.2.2");
c1.join();
c2.join();
c3.join();
m1.join();
m2.join();
return 0;
}