OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
DoubleDictionaryThreadAbortSafe.cs
Go to the documentation of this file.
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 {
40  public class DoubleDictionaryThreadAbortSafe<TKey1, TKey2, TValue>
41  {
42  Dictionary<TKey1, TValue> Dictionary1;
43  Dictionary<TKey2, TValue> Dictionary2;
44  ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
45 
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 }
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
Definition: ICM_Api.cs:31