aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llkeythrottle.h
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:45:18 -0500
committerJacek Antonelli2008-08-15 23:45:18 -0500
commitad2310656299467c775738fcdbc5840bd492df8d (patch)
tree61a3e7b568d04f12e7a42c962828e9334954811d /linden/indra/llcommon/llkeythrottle.h
parentSecond Life viewer sources 1.18.5.1-RC (diff)
downloadmeta-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.h218
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
38template <class T>
39class LLKeyThrottleImpl
40{
41public:
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
72template< class T >
73class LLKeyThrottle
74{
75public:
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
214protected:
215 LLKeyThrottleImpl<T>& m;
216};
217
218#endif