clockwerk-opensim-stable – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2008, openmetaverse.org, http://opensimulator.org/
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Threading;
29 using System.Collections.Generic;
30  
31 namespace OpenSim.Framework
32 {
33 /// <summary>
34 /// A double dictionary that is thread abort safe.
35 /// </summary>
36 /// <remarks>
37 /// This adapts OpenMetaverse.DoubleDictionary to be thread-abort safe by acquiring ReaderWriterLockSlim within
38 /// a finally section (which can't be interrupted by Thread.Abort()).
39 /// </remarks>
40 public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
41 {
42 Dictionary<TKey1, TValue> Dictionary1;
43 Dictionary<TKey2, TValue> Dictionary2;
44 ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
45  
46 public DoubleDictionaryThreadAbortSafe()
47 {
48 Dictionary1 = new Dictionary<TKey1,TValue>();
49 Dictionary2 = new Dictionary<TKey2,TValue>();
50 }
51  
52 public DoubleDictionaryThreadAbortSafe(int capacity)
53 {
54 Dictionary1 = new Dictionary<TKey1, TValue>(capacity);
55 Dictionary2 = new Dictionary<TKey2, TValue>(capacity);
56 }
57  
58 public void Add(TKey1 key1, TKey2 key2, TValue value)
59 {
60 bool gotLock = false;
61  
62 try
63 {
64 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
65 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
66 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
67 try {}
68 finally
69 {
70 rwLock.EnterWriteLock();
71 gotLock = true;
72 }
73  
74 if (Dictionary1.ContainsKey(key1))
75 {
76 if (!Dictionary2.ContainsKey(key2))
77 throw new ArgumentException("key1 exists in the dictionary but not key2");
78 }
79 else if (Dictionary2.ContainsKey(key2))
80 {
81 if (!Dictionary1.ContainsKey(key1))
82 throw new ArgumentException("key2 exists in the dictionary but not key1");
83 }
84  
85 Dictionary1[key1] = value;
86 Dictionary2[key2] = value;
87 }
88 finally
89 {
90 if (gotLock)
91 rwLock.ExitWriteLock();
92 }
93 }
94  
95 public bool Remove(TKey1 key1, TKey2 key2)
96 {
97 bool success;
98 bool gotLock = false;
99  
100 try
101 {
102 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
103 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
104 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
105 try {}
106 finally
107 {
108 rwLock.EnterWriteLock();
109 gotLock = true;
110 }
111  
112 Dictionary1.Remove(key1);
113 success = Dictionary2.Remove(key2);
114 }
115 finally
116 {
117 if (gotLock)
118 rwLock.ExitWriteLock();
119 }
120  
121 return success;
122 }
123  
124 public bool Remove(TKey1 key1)
125 {
126 bool found = false;
127 bool gotLock = false;
128  
129 try
130 {
131 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
132 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
133 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
134 try {}
135 finally
136 {
137 rwLock.EnterWriteLock();
138 gotLock = true;
139 }
140  
141 // This is an O(n) operation!
142 TValue value;
143 if (Dictionary1.TryGetValue(key1, out value))
144 {
145 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
146 {
147 if (kvp.Value.Equals(value))
148 {
149 Dictionary1.Remove(key1);
150 Dictionary2.Remove(kvp.Key);
151 found = true;
152 break;
153 }
154 }
155 }
156 }
157 finally
158 {
159 if (gotLock)
160 rwLock.ExitWriteLock();
161 }
162  
163 return found;
164 }
165  
166 public bool Remove(TKey2 key2)
167 {
168 bool found = false;
169 bool gotLock = false;
170  
171 try
172 {
173 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
174 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
175 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
176 try {}
177 finally
178 {
179 rwLock.EnterWriteLock();
180 gotLock = true;
181 }
182  
183 // This is an O(n) operation!
184 TValue value;
185 if (Dictionary2.TryGetValue(key2, out value))
186 {
187 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
188 {
189 if (kvp.Value.Equals(value))
190 {
191 Dictionary2.Remove(key2);
192 Dictionary1.Remove(kvp.Key);
193 found = true;
194 break;
195 }
196 }
197 }
198 }
199 finally
200 {
201 if (gotLock)
202 rwLock.ExitWriteLock();
203 }
204  
205 return found;
206 }
207  
208 public void Clear()
209 {
210 bool gotLock = false;
211  
212 try
213 {
214 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
215 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
216 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
217 try {}
218 finally
219 {
220 rwLock.EnterWriteLock();
221 gotLock = true;
222 }
223  
224 Dictionary1.Clear();
225 Dictionary2.Clear();
226 }
227 finally
228 {
229 if (gotLock)
230 rwLock.ExitWriteLock();
231 }
232 }
233  
234 public int Count
235 {
236 get { return Dictionary1.Count; }
237 }
238  
239 public bool ContainsKey(TKey1 key)
240 {
241 return Dictionary1.ContainsKey(key);
242 }
243  
244 public bool ContainsKey(TKey2 key)
245 {
246 return Dictionary2.ContainsKey(key);
247 }
248  
249 public bool TryGetValue(TKey1 key, out TValue value)
250 {
251 bool success;
252 bool gotLock = false;
253  
254 try
255 {
256 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
257 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
258 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
259 try {}
260 finally
261 {
262 rwLock.EnterReadLock();
263 gotLock = true;
264 }
265  
266 success = Dictionary1.TryGetValue(key, out value);
267 }
268 finally
269 {
270 if (gotLock)
271 rwLock.ExitReadLock();
272 }
273  
274 return success;
275 }
276  
277 public bool TryGetValue(TKey2 key, out TValue value)
278 {
279 bool success;
280 bool gotLock = false;
281  
282 try
283 {
284 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
285 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
286 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
287 try {}
288 finally
289 {
290 rwLock.EnterReadLock();
291 gotLock = true;
292 }
293  
294 success = Dictionary2.TryGetValue(key, out value);
295 }
296 finally
297 {
298 if (gotLock)
299 rwLock.ExitReadLock();
300 }
301  
302 return success;
303 }
304  
305 public void ForEach(Action<TValue> action)
306 {
307 bool gotLock = false;
308  
309 try
310 {
311 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
312 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
313 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
314 try {}
315 finally
316 {
317 rwLock.EnterReadLock();
318 gotLock = true;
319 }
320  
321 foreach (TValue value in Dictionary1.Values)
322 action(value);
323 }
324 finally
325 {
326 if (gotLock)
327 rwLock.ExitReadLock();
328 }
329 }
330  
331 public void ForEach(Action<KeyValuePair<TKey1, TValue>> action)
332 {
333 bool gotLock = false;
334  
335 try
336 {
337 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
338 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
339 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
340 try {}
341 finally
342 {
343 rwLock.EnterReadLock();
344 gotLock = true;
345 }
346  
347 foreach (KeyValuePair<TKey1, TValue> entry in Dictionary1)
348 action(entry);
349 }
350 finally
351 {
352 if (gotLock)
353 rwLock.ExitReadLock();
354 }
355 }
356  
357 public void ForEach(Action<KeyValuePair<TKey2, TValue>> action)
358 {
359 bool gotLock = false;
360  
361 try
362 {
363 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
364 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
365 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
366 try {}
367 finally
368 {
369 rwLock.EnterReadLock();
370 gotLock = true;
371 }
372  
373 foreach (KeyValuePair<TKey2, TValue> entry in Dictionary2)
374 action(entry);
375 }
376 finally
377 {
378 if (gotLock)
379 rwLock.ExitReadLock();
380 }
381 }
382  
383 public TValue FindValue(Predicate<TValue> predicate)
384 {
385 bool gotLock = false;
386  
387 try
388 {
389 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
390 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
391 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
392 try {}
393 finally
394 {
395 rwLock.EnterReadLock();
396 gotLock = true;
397 }
398  
399 foreach (TValue value in Dictionary1.Values)
400 {
401 if (predicate(value))
402 return value;
403 }
404 }
405 finally
406 {
407 if (gotLock)
408 rwLock.ExitReadLock();
409 }
410  
411 return default(TValue);
412 }
413  
414 public IList<TValue> FindAll(Predicate<TValue> predicate)
415 {
416 IList<TValue> list = new List<TValue>();
417 bool gotLock = false;
418  
419 try
420 {
421 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
422 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
423 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
424 try {}
425 finally
426 {
427 rwLock.EnterReadLock();
428 gotLock = true;
429 }
430  
431 foreach (TValue value in Dictionary1.Values)
432 {
433 if (predicate(value))
434 list.Add(value);
435 }
436 }
437 finally
438 {
439 if (gotLock)
440 rwLock.ExitReadLock();
441 }
442  
443 return list;
444 }
445  
446 public int RemoveAll(Predicate<TValue> predicate)
447 {
448 IList<TKey1> list = new List<TKey1>();
449 bool gotUpgradeableLock = false;
450  
451 try
452 {
453 // Avoid an asynchronous Thread.Abort() from possibly never existing an acquired lock by placing
454 // the acquision inside the main try. The inner finally block is needed because thread aborts cannot
455 // interrupt code in these blocks (hence gotLock is guaranteed to be set correctly).
456 try {}
457 finally
458 {
459 rwLock.EnterUpgradeableReadLock();
460 gotUpgradeableLock = true;
461 }
462  
463 foreach (KeyValuePair<TKey1, TValue> kvp in Dictionary1)
464 {
465 if (predicate(kvp.Value))
466 list.Add(kvp.Key);
467 }
468  
469 IList<TKey2> list2 = new List<TKey2>(list.Count);
470 foreach (KeyValuePair<TKey2, TValue> kvp in Dictionary2)
471 {
472 if (predicate(kvp.Value))
473 list2.Add(kvp.Key);
474 }
475  
476 bool gotWriteLock = false;
477  
478 try
479 {
480 try {}
481 finally
482 {
483 rwLock.EnterUpgradeableReadLock();
484 gotWriteLock = true;
485 }
486  
487 for (int i = 0; i < list.Count; i++)
488 Dictionary1.Remove(list[i]);
489  
490 for (int i = 0; i < list2.Count; i++)
491 Dictionary2.Remove(list2[i]);
492 }
493 finally
494 {
495 if (gotWriteLock)
496 rwLock.ExitWriteLock();
497 }
498 }
499 finally
500 {
501 if (gotUpgradeableLock)
502 rwLock.ExitUpgradeableReadLock();
503 }
504  
505 return list.Count;
506 }
507 }
508 }