diff options
author | Jacek Antonelli | 2008-08-15 23:45:18 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:45:18 -0500 |
commit | ad2310656299467c775738fcdbc5840bd492df8d (patch) | |
tree | 61a3e7b568d04f12e7a42c962828e9334954811d /linden/indra/llcommon/llkeythrottle.h | |
parent | Second Life viewer sources 1.18.5.1-RC (diff) | |
download | meta-impy-ad2310656299467c775738fcdbc5840bd492df8d.zip meta-impy-ad2310656299467c775738fcdbc5840bd492df8d.tar.gz meta-impy-ad2310656299467c775738fcdbc5840bd492df8d.tar.bz2 meta-impy-ad2310656299467c775738fcdbc5840bd492df8d.tar.xz |
Second Life viewer sources 1.18.5.2-RC
Diffstat (limited to 'linden/indra/llcommon/llkeythrottle.h')
-rw-r--r-- | linden/indra/llcommon/llkeythrottle.h | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/linden/indra/llcommon/llkeythrottle.h b/linden/indra/llcommon/llkeythrottle.h new file mode 100644 index 0000000..ded9e17 --- /dev/null +++ b/linden/indra/llcommon/llkeythrottle.h | |||
@@ -0,0 +1,218 @@ | |||
1 | /** | ||
2 | * @file llkeythrottle.h | ||
3 | * @brief LLKeyThrottle class definition | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2005&license=internal$ | ||
6 | * | ||
7 | * Copyright (c) 2005-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of | ||
10 | * this source code is governed by the Linden Lab Source Code Disclosure | ||
11 | * Agreement ("Agreement") previously entered between you and Linden | ||
12 | * Lab. By accessing, using, copying, modifying or distributing this | ||
13 | * software, you acknowledge that you have been informed of your | ||
14 | * obligations under the Agreement and agree to abide by those obligations. | ||
15 | * | ||
16 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
17 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
18 | * COMPLETENESS OR PERFORMANCE. | ||
19 | * $/LicenseInfo$ | ||
20 | */ | ||
21 | |||
22 | #ifndef LL_LLKEY_THROTTLE_H | ||
23 | #define LL_LLKEY_THROTTLE_H | ||
24 | |||
25 | // LLKeyThrottle keeps track of the number of action occurences with a key value | ||
26 | // for a type over a given time period. If the rate set in the constructor is | ||
27 | // exceeed, the key is considered blocked. The transition from unblocked to | ||
28 | // blocked is noted so the responsible agent can be informed. This transition | ||
29 | // takes twice the look back window to clear. | ||
30 | |||
31 | #include "linden_common.h" | ||
32 | |||
33 | #include "llframetimer.h" | ||
34 | #include <map> | ||
35 | |||
36 | |||
37 | // Implementation utility class - use LLKeyThrottle, not this | ||
38 | template <class T> | ||
39 | class LLKeyThrottleImpl | ||
40 | { | ||
41 | public: | ||
42 | struct Entry { | ||
43 | U32 count; | ||
44 | BOOL blocked; | ||
45 | |||
46 | Entry() : count(0), blocked(FALSE) { } | ||
47 | }; | ||
48 | |||
49 | typedef std::map<T, Entry> EntryMap; | ||
50 | |||
51 | EntryMap * prevMap; | ||
52 | EntryMap * currMap; | ||
53 | |||
54 | U32 countLimit; | ||
55 | // maximum number of keys allowed per interval | ||
56 | |||
57 | U64 interval_usec; | ||
58 | // each map covers this time period | ||
59 | U64 start_usec; | ||
60 | // currMap started counting at this time | ||
61 | // prevMap covers the previous interval | ||
62 | |||
63 | LLKeyThrottleImpl() : prevMap(0), currMap(0) { } | ||
64 | |||
65 | static U64 getTime() | ||
66 | { | ||
67 | return LLFrameTimer::getTotalTime(); | ||
68 | } | ||
69 | }; | ||
70 | |||
71 | |||
72 | template< class T > | ||
73 | class LLKeyThrottle | ||
74 | { | ||
75 | public: | ||
76 | LLKeyThrottle(U32 limit, F32 interval) | ||
77 | : m(* new LLKeyThrottleImpl<T>) | ||
78 | { | ||
79 | // limit is the maximum number of keys | ||
80 | // allowed per interval (in seconds) | ||
81 | m.countLimit = limit; | ||
82 | m.interval_usec = (U64)(interval * USEC_PER_SEC); | ||
83 | m.start_usec = LLKeyThrottleImpl<T>::getTime(); | ||
84 | |||
85 | m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; | ||
86 | m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; | ||
87 | } | ||
88 | |||
89 | ~LLKeyThrottle() | ||
90 | { | ||
91 | delete m.prevMap; | ||
92 | delete m.currMap; | ||
93 | delete &m; | ||
94 | } | ||
95 | |||
96 | enum State { | ||
97 | THROTTLE_OK, // rate not exceeded, let pass | ||
98 | THROTTLE_NEWLY_BLOCKED, // rate exceed for the first time | ||
99 | THROTTLE_BLOCKED, // rate exceed, block key | ||
100 | }; | ||
101 | |||
102 | // call each time the key wants use | ||
103 | State noteAction(const T& id, S32 weight = 1) | ||
104 | { | ||
105 | U64 now = LLKeyThrottleImpl<T>::getTime(); | ||
106 | |||
107 | if (now >= (m.start_usec + m.interval_usec)) | ||
108 | { | ||
109 | if (now < (m.start_usec + 2 * m.interval_usec)) | ||
110 | { | ||
111 | // prune old data | ||
112 | delete m.prevMap; | ||
113 | m.prevMap = m.currMap; | ||
114 | m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; | ||
115 | |||
116 | m.start_usec += m.interval_usec; | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | // lots of time has passed, all data is stale | ||
121 | delete m.prevMap; | ||
122 | delete m.currMap; | ||
123 | m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; | ||
124 | m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; | ||
125 | |||
126 | m.start_usec = now; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | U32 prevCount = 0; | ||
131 | BOOL prevBlocked = FALSE; | ||
132 | |||
133 | typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); | ||
134 | if (prev != m.prevMap->end()) | ||
135 | { | ||
136 | prevCount = prev->second.count; | ||
137 | prevBlocked = prev->second.blocked; | ||
138 | } | ||
139 | |||
140 | typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; | ||
141 | |||
142 | bool wereBlocked = curr.blocked || prevBlocked; | ||
143 | |||
144 | curr.count += weight; | ||
145 | |||
146 | // curr.count is the number of keys in | ||
147 | // this current 'time slice' from the beginning of it until now | ||
148 | // prevCount is the number of keys in the previous | ||
149 | // time slice scaled to be one full time slice back from the current | ||
150 | // (now) time. | ||
151 | |||
152 | // compute current, windowed rate | ||
153 | F64 timeInCurrent = ((F64)(now - m.start_usec) / m.interval_usec); | ||
154 | F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); | ||
155 | |||
156 | curr.blocked |= averageCount > m.countLimit; | ||
157 | |||
158 | bool nowBlocked = curr.blocked || prevBlocked; | ||
159 | |||
160 | if (!nowBlocked) | ||
161 | { | ||
162 | return THROTTLE_OK; | ||
163 | } | ||
164 | else if (!wereBlocked) | ||
165 | { | ||
166 | return THROTTLE_NEWLY_BLOCKED; | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | return THROTTLE_BLOCKED; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | // call to force throttle conditions for id | ||
175 | void throttleAction(const T& id) | ||
176 | { | ||
177 | noteAction(id); | ||
178 | typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; | ||
179 | if (curr.count < m.countLimit) | ||
180 | { | ||
181 | curr.count = m.countLimit; | ||
182 | } | ||
183 | curr.blocked = TRUE; | ||
184 | } | ||
185 | |||
186 | // returns TRUE if key is blocked | ||
187 | BOOL isThrottled(const T& id) const | ||
188 | { | ||
189 | if (m.currMap->empty() | ||
190 | && m.prevMap->empty()) | ||
191 | { | ||
192 | // most of the time we'll fall in here | ||
193 | return FALSE; | ||
194 | } | ||
195 | |||
196 | // NOTE, we ignore the case where id is in the map but the map is stale. | ||
197 | // You might think that we'd stop throttling things in such a case, | ||
198 | // however it may be that a god has disabled scripts in the region or | ||
199 | // estate --> we probably want to report the state of the id when the | ||
200 | // scripting engine was paused. | ||
201 | typename LLKeyThrottleImpl<T>::EntryMap::const_iterator entry = m.currMap->find(id); | ||
202 | if (entry != m.currMap->end()) | ||
203 | { | ||
204 | return entry->second.blocked; | ||
205 | } | ||
206 | entry = m.prevMap->find(id); | ||
207 | if (entry != m.prevMap->end()) | ||
208 | { | ||
209 | return entry->second.blocked; | ||
210 | } | ||
211 | return FALSE; | ||
212 | } | ||
213 | |||
214 | protected: | ||
215 | LLKeyThrottleImpl<T>& m; | ||
216 | }; | ||
217 | |||
218 | #endif | ||