OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
CnmMemoryCache.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
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  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Diagnostics;
32 
33 namespace OpenSim.Framework
34 {
52  public class CnmMemoryCache<TKey, TValue> : ICnmCache<TKey, TValue>
53  {
58  public const int DefaultMaxCount = 4096;
59 
69  public const long DefaultMaxSize = 134217728;
70 
74  private const int DefaultOperationsBetweenTimeChecks = 40;
75 
84  public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes(30.0);
85 
94  public static readonly TimeSpan MinExpirationTime = TimeSpan.FromSeconds(10.0);
95 
103  public readonly IEqualityComparer<TKey> Comparer;
104 
108  private TimeSpan m_expirationTime = DefaultExpirationTime;
109 
113  private int m_generationBucketCount;
114 
118  private int m_generationElementCount;
119 
123  private long m_generationMaxSize;
124 
128  private int m_maxCount;
129 
133  private long m_maxElementSize;
134 
138  private long m_maxSize;
139 
143  private IGeneration m_newGeneration;
144 
148  private IGeneration m_oldGeneration;
149 
153  private int m_operationsBetweenTimeChecks = DefaultOperationsBetweenTimeChecks;
154 
158  private readonly object m_syncRoot = new object();
159 
168  private int m_version;
169 
173  public CnmMemoryCache()
174  : this(DefaultMaxSize)
175  {
176  }
177 
184  public CnmMemoryCache(long maximalSize)
185  : this(maximalSize, DefaultMaxCount)
186  {
187  }
188 
198  public CnmMemoryCache(long maximalSize, int maximalCount)
199  : this(maximalSize, maximalCount, DefaultExpirationTime)
200  {
201  }
202 
215  public CnmMemoryCache(long maximalSize, int maximalCount, TimeSpan expirationTime)
216  : this(maximalSize, maximalCount, expirationTime, EqualityComparer<TKey>.Default)
217  {
218  }
219 
238  public CnmMemoryCache(long maximalSize,
239  int maximalCount,
240  TimeSpan expirationTime,
241  IEqualityComparer<TKey> comparer)
242  {
243  if (comparer == null)
244  throw new ArgumentNullException("comparer");
245 
246  if (expirationTime < MinExpirationTime)
247  expirationTime = MinExpirationTime;
248  if (maximalCount < 8)
249  maximalCount = 8;
250  if (maximalSize < 8)
251  maximalSize = 8;
252  if (maximalCount > maximalSize)
253  maximalCount = (int) maximalSize;
254 
255  Comparer = comparer;
256  m_expirationTime = expirationTime;
257  m_maxSize = maximalSize;
258  m_maxCount = maximalCount;
259 
260  Initialize();
261  }
262 
278  protected virtual void AddToNewGeneration(int bucketIndex, TKey key, TValue value, long size)
279  {
280  // Add to newest generation
281  if (!m_newGeneration.Set(bucketIndex, key, value, size))
282  {
283  // Failed to add new generation
284  RecycleGenerations();
285  m_newGeneration.Set(bucketIndex, key, value, size);
286  }
287 
288  m_version++;
289  }
290 
317  protected virtual int GetBucketIndex(TKey key)
318  {
319  return (Comparer.GetHashCode(key) & 0x7FFFFFFF) % m_generationBucketCount;
320  }
321 
328  protected virtual void PurgeGeneration(IGeneration generation)
329  {
330  generation.Clear();
331  m_version++;
332  }
333 
337  private void CheckExpired()
338  {
339  // Do this only one in every m_operationsBetweenTimeChecks
340  // Fetching time is using several millisecons - it is better not to do all time.
341  m_operationsBetweenTimeChecks--;
342  if (m_operationsBetweenTimeChecks <= 0)
343  PurgeExpired();
344  }
345 
349  private void Initialize()
350  {
351  m_version++;
352 
353  m_generationMaxSize = MaxSize / 2;
354  MaxElementSize = MaxSize / 8;
355  m_generationElementCount = MaxCount / 2;
356 
357  // Buckets need to be prime number to get better spread of hash values
358  m_generationBucketCount = PrimeNumberHelper.GetPrime(m_generationElementCount);
359 
360  m_newGeneration = new HashGeneration(this);
361  m_oldGeneration = new HashGeneration(this);
362  m_oldGeneration.MakeOld();
363  }
364 
368  private void RecycleGenerations()
369  {
370  // Rotate old generation to new generation, new generation to old generation
371  IGeneration temp = m_newGeneration;
372  m_newGeneration = m_oldGeneration;
373  m_newGeneration.Clear();
374  m_oldGeneration = temp;
375  m_oldGeneration.MakeOld();
376  }
377 
378  #region Nested type: Enumerator
379 
383  private class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
384  {
388  private int m_currentEnumerator = -1;
389 
393  private readonly IEnumerator<KeyValuePair<TKey, TValue>>[] m_generationEnumerators =
394  new IEnumerator<KeyValuePair<TKey, TValue>>[2];
395 
402  public Enumerator(CnmMemoryCache<TKey, TValue> cache)
403  {
404  m_generationEnumerators[ 0 ] = cache.m_newGeneration.GetEnumerator();
405  m_generationEnumerators[ 1 ] = cache.m_oldGeneration.GetEnumerator();
406  }
407 
408  #region IEnumerator<KeyValuePair<TKey,TValue>> Members
409 
419  public KeyValuePair<TKey, TValue> Current
420  {
421  get
422  {
423  if (m_currentEnumerator == -1 || m_currentEnumerator >= m_generationEnumerators.Length)
424  throw new InvalidOperationException();
425 
426  return m_generationEnumerators[ m_currentEnumerator ].Current;
427  }
428  }
429 
439  object IEnumerator.Current
440  {
441  get { return Current; }
442  }
443 
448  public void Dispose()
449  {
450  }
451 
462  public bool MoveNext()
463  {
464  if (m_currentEnumerator == -1)
465  m_currentEnumerator = 0;
466 
467  while (m_currentEnumerator < m_generationEnumerators.Length)
468  {
469  if (m_generationEnumerators[ m_currentEnumerator ].MoveNext())
470  return true;
471 
472  m_currentEnumerator++;
473  }
474 
475  return false;
476  }
477 
485  public void Reset()
486  {
487  foreach (IEnumerator<KeyValuePair<TKey, TValue>> enumerator in m_generationEnumerators)
488  {
489  enumerator.Reset();
490  }
491 
492  m_currentEnumerator = -1;
493  }
494 
495  #endregion
496  }
497 
498  #endregion
499 
500  #region Nested type: HashGeneration
501 
515  private class HashGeneration : IGeneration
516  {
520  private bool m_accessedSinceLastTimeCheck;
521 
532  private readonly int[] m_buckets;
533 
537  private readonly CnmMemoryCache<TKey, TValue> m_cache;
538 
543  private readonly Element[] m_elements;
544 
548  private DateTime m_expirationTime1;
549 
553  private int m_firstFreeElement;
554 
562  private int m_freeCount;
563 
567  private bool m_newGeneration;
568 
572  private int m_nextUnusedElement;
573 
577  private long m_size;
578 
585  public HashGeneration(CnmMemoryCache<TKey, TValue> cache)
586  {
587  m_cache = cache;
588  m_elements = new Element[m_cache.m_generationElementCount];
589  m_buckets = new int[m_cache.m_generationBucketCount];
590  Clear();
591  }
592 
611  private int FindElementIndex(int bucketIndex, TKey key, bool moveToFront, out int previousIndex)
612  {
613  previousIndex = -1;
614  int elementIndex = m_buckets[ bucketIndex ];
615  while (elementIndex >= 0)
616  {
617  if (m_cache.Comparer.Equals(key, m_elements[ elementIndex ].Key))
618  {
619  // Found match
620  if (moveToFront && previousIndex >= 0)
621  {
622  // Move entry to front
623  m_elements[ previousIndex ].Next = m_elements[ elementIndex ].Next;
624  m_elements[ elementIndex ].Next = m_buckets[ bucketIndex ];
625  m_buckets[ bucketIndex ] = elementIndex;
626  previousIndex = 0;
627  }
628 
629  return elementIndex;
630  }
631 
632  previousIndex = elementIndex;
633  elementIndex = m_elements[ elementIndex ].Next;
634  }
635 
636  return -1;
637  }
638 
651  private void RemoveElement(int bucketIndex, int entryIndex, int previousIndex)
652  {
653  if (previousIndex >= 0)
654  m_elements[ previousIndex ].Next = m_elements[ entryIndex ].Next;
655  else
656  m_buckets[ bucketIndex ] = m_elements[ entryIndex ].Next;
657 
658  Size -= m_elements[ entryIndex ].Size;
659  m_elements[ entryIndex ].Value = default(TValue);
660  m_elements[ entryIndex ].Key = default(TKey);
661 
662  // Add element to free elements list
663  m_elements[ entryIndex ].Next = m_firstFreeElement;
664  m_firstFreeElement = entryIndex;
665  m_freeCount++;
666  }
667 
668  #region Nested type: Element
669 
673  private struct Element
674  {
678  public TKey Key;
679 
688  public int Next;
689 
696  public long Size;
697 
705  public TValue Value;
706 
713  public bool IsFree
714  {
715  get { return Size == 0; }
716  }
717  }
718 
719  #endregion
720 
721  #region Nested type: Enumerator
722 
726  private class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
727  {
731  private KeyValuePair<TKey, TValue> m_current;
732 
736  private int m_currentIndex;
737 
741  private readonly HashGeneration m_generation;
742 
750  private readonly int m_version;
751 
758  public Enumerator(HashGeneration generation)
759  {
760  m_generation = generation;
761  m_version = m_generation.m_cache.m_version;
762  }
763 
764  #region IEnumerator<KeyValuePair<TKey,TValue>> Members
765 
775  public KeyValuePair<TKey, TValue> Current
776  {
777  get
778  {
779  if (m_currentIndex == 0 || m_currentIndex >= m_generation.Count)
780  throw new InvalidOperationException();
781 
782  return m_current;
783  }
784  }
785 
795  object IEnumerator.Current
796  {
797  get { return Current; }
798  }
799 
804  public void Dispose()
805  {
806  }
807 
817  public bool MoveNext()
818  {
819  if (m_version != m_generation.m_cache.m_version)
820  throw new InvalidOperationException();
821 
822  while (m_currentIndex < m_generation.Count)
823  {
824  if (m_generation.m_elements[ m_currentIndex ].IsFree)
825  {
826  m_currentIndex++;
827  continue;
828  }
829 
830  m_current = new KeyValuePair<TKey, TValue>(m_generation.m_elements[ m_currentIndex ].Key,
831  m_generation.m_elements[ m_currentIndex ].Value);
832  m_currentIndex++;
833  return true;
834  }
835 
836  m_current = new KeyValuePair<TKey, TValue>();
837  return false;
838  }
839 
847  public void Reset()
848  {
849  if (m_version != m_generation.m_cache.m_version)
850  throw new InvalidOperationException();
851 
852  m_currentIndex = 0;
853  }
854 
855  #endregion
856  }
857 
858  #endregion
859 
860  #region IGeneration Members
861 
865  public bool AccessedSinceLastTimeCheck
866  {
867  get { return m_accessedSinceLastTimeCheck; }
868 
869  set { m_accessedSinceLastTimeCheck = value; }
870  }
871 
875  public int Count
876  {
877  get { return m_nextUnusedElement - m_freeCount; }
878  }
879 
883  public DateTime ExpirationTime
884  {
885  get { return m_expirationTime1; }
886 
887  set { m_expirationTime1 = value; }
888  }
889 
893  public long Size
894  {
895  get { return m_size; }
896 
897  private set { m_size = value; }
898  }
899 
908  public void Clear()
909  {
910  for (int i = m_buckets.Length - 1 ; i >= 0 ; i--)
911  {
912  m_buckets[ i ] = -1;
913  }
914 
915  Array.Clear(m_elements, 0, m_elements.Length);
916  Size = 0;
917  m_firstFreeElement = -1;
918  m_freeCount = 0;
919  m_nextUnusedElement = 0;
920  m_newGeneration = true;
921  ExpirationTime = DateTime.MaxValue;
922  }
923 
937  public bool Contains(int bucketIndex, TKey key)
938  {
939  int previousIndex;
940  if (FindElementIndex(bucketIndex, key, true, out previousIndex) == -1)
941  return false;
942 
943  AccessedSinceLastTimeCheck = true;
944  return true;
945  }
946 
954  public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
955  {
956  return new Enumerator(this);
957  }
958 
966  public void MakeOld()
967  {
968  m_newGeneration = false;
969  }
970 
983  public bool Remove(int bucketIndex, TKey key)
984  {
985  int previousIndex;
986  int entryIndex = FindElementIndex(bucketIndex, key, false, out previousIndex);
987  if (entryIndex != -1)
988  {
989  RemoveElement(bucketIndex, entryIndex, previousIndex);
990  AccessedSinceLastTimeCheck = true;
991  return true;
992  }
993 
994  return false;
995  }
996 
1023  public bool Set(int bucketIndex, TKey key, TValue value, long size)
1024  {
1025  Debug.Assert(m_newGeneration, "It is possible to insert new elements only to newest generation.");
1026  Debug.Assert(size > 0, "New element size should be more than 0.");
1027 
1028  int previousIndex;
1029  int elementIndex = FindElementIndex(bucketIndex, key, true, out previousIndex);
1030  if (elementIndex == -1)
1031  {
1032  // New key
1033  if (Size + size > m_cache.m_generationMaxSize ||
1034  (m_nextUnusedElement == m_cache.m_generationElementCount && m_freeCount == 0))
1035  {
1036  // Generation is full
1037  return false;
1038  }
1039 
1040  // Increase size of generation
1041  Size += size;
1042 
1043  // Get first free entry and update free entry list
1044  if (m_firstFreeElement != -1)
1045  {
1046  // There was entry that was removed
1047  elementIndex = m_firstFreeElement;
1048  m_firstFreeElement = m_elements[ elementIndex ].Next;
1049  m_freeCount--;
1050  }
1051  else
1052  {
1053  // No entries removed so far - just take a last one
1054  elementIndex = m_nextUnusedElement;
1055  m_nextUnusedElement++;
1056  }
1057 
1058  Debug.Assert(m_elements[ elementIndex ].IsFree, "Allocated element is not free.");
1059 
1060  // Move new entry to front
1061  m_elements[ elementIndex ].Next = m_buckets[ bucketIndex ];
1062  m_buckets[ bucketIndex ] = elementIndex;
1063 
1064  // Set key and update count
1065  m_elements[ elementIndex ].Key = key;
1066  }
1067  else
1068  {
1069  // Existing key
1070  if (Size - m_elements[ elementIndex ].Size + size > m_cache.m_generationMaxSize)
1071  {
1072  // Generation is full
1073  // Remove existing element, because generation is going to be recycled to
1074  // old generation and element is stored to new generation
1075  RemoveElement(bucketIndex, elementIndex, previousIndex);
1076  return false;
1077  }
1078 
1079  // Update generation's size
1080  Size = Size - m_elements[ elementIndex ].Size + size;
1081  }
1082 
1083  // Finally set value and size
1084  m_elements[ elementIndex ].Value = value;
1085  m_elements[ elementIndex ].Size = size;
1086 
1087  // Success - key was inserterted to generation
1088  AccessedSinceLastTimeCheck = true;
1089  return true;
1090  }
1091 
1116  public bool TryGetValue(int bucketIndex, TKey key, out TValue value, out long size)
1117  {
1118  // Find entry index,
1119  int previousIndex;
1120  int elementIndex = FindElementIndex(bucketIndex, key, m_newGeneration, out previousIndex);
1121  if (elementIndex == -1)
1122  {
1123  value = default(TValue);
1124  size = 0;
1125  return false;
1126  }
1127 
1128  value = m_elements[ elementIndex ].Value;
1129  size = m_elements[ elementIndex ].Size;
1130 
1131  if (!m_newGeneration)
1132  {
1133  // Old generation - remove element, because it is moved to new generation
1134  RemoveElement(bucketIndex, elementIndex, previousIndex);
1135  }
1136 
1137  AccessedSinceLastTimeCheck = true;
1138  return true;
1139  }
1140 
1148  IEnumerator IEnumerable.GetEnumerator()
1149  {
1150  return GetEnumerator();
1151  }
1152 
1153  #endregion
1154  }
1155 
1156  #endregion
1157 
1158  #region Nested type: IGeneration
1159 
1172  protected interface IGeneration : IEnumerable<KeyValuePair<TKey, TValue>>
1173  {
1177  bool AccessedSinceLastTimeCheck { get; set; }
1178 
1182  int Count { get; }
1183 
1187  DateTime ExpirationTime { get; set; }
1188 
1192  long Size { get; }
1193 
1202  void Clear();
1203 
1217  bool Contains(int bucketIndex, TKey key);
1218 
1226  void MakeOld();
1227 
1240  bool Remove(int bucketIndex, TKey key);
1241 
1268  bool Set(int bucketIndex, TKey key, TValue value, long size);
1269 
1294  bool TryGetValue(int bucketIndex, TKey key, out TValue value, out long size);
1295  }
1296 
1297  #endregion
1298 
1299  #region ICnmCache<TKey,TValue> Members
1300 
1314  public int Count
1315  {
1316  get { return m_newGeneration.Count + m_oldGeneration.Count; }
1317  }
1318 
1354  public TimeSpan ExpirationTime
1355  {
1356  get { return m_expirationTime; }
1357 
1358  set
1359  {
1360  if (value < MinExpirationTime)
1361  value = MinExpirationTime;
1362 
1363  if (m_expirationTime == value)
1364  return;
1365 
1366  m_newGeneration.ExpirationTime = (m_newGeneration.ExpirationTime - m_expirationTime) + value;
1367  m_oldGeneration.ExpirationTime = (m_oldGeneration.ExpirationTime - m_expirationTime) + value;
1368  m_expirationTime = value;
1369 
1370  PurgeExpired();
1371  }
1372  }
1373 
1391  public bool IsCountLimited
1392  {
1393  get { return true; }
1394  }
1395 
1414  public bool IsSizeLimited
1415  {
1416  get { return true; }
1417  }
1418 
1435  public bool IsSynchronized
1436  {
1437  get { return false; }
1438  }
1439 
1457  public bool IsTimeLimited
1458  {
1459  get { return ExpirationTime != TimeSpan.MaxValue; }
1460  }
1461 
1475  public int MaxCount
1476  {
1477  get { return m_maxCount; }
1478 
1479  set
1480  {
1481  if (value < 8)
1482  value = 8;
1483  if (m_maxCount == value)
1484  return;
1485 
1486  m_maxCount = value;
1487  Initialize();
1488  }
1489  }
1490 
1507  public long MaxElementSize
1508  {
1509  get { return m_maxElementSize; }
1510 
1511  private set { m_maxElementSize = value; }
1512  }
1513 
1532  public long MaxSize
1533  {
1534  get { return m_maxSize; }
1535 
1536  set
1537  {
1538  if (value < 8)
1539  value = 8;
1540  if (m_maxSize == value)
1541  return;
1542 
1543  m_maxSize = value;
1544  Initialize();
1545  }
1546  }
1547 
1571  public long Size
1572  {
1573  get { return m_newGeneration.Size + m_oldGeneration.Size; }
1574  }
1575 
1591  public object SyncRoot
1592  {
1593  get { return m_syncRoot; }
1594  }
1595 
1604  public void Clear()
1605  {
1606  m_newGeneration.Clear();
1607  m_oldGeneration.Clear();
1608  m_oldGeneration.MakeOld();
1609  m_version++;
1610  }
1611 
1619  public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
1620  {
1621  return new Enumerator(this);
1622  }
1623 
1643  public void PurgeExpired()
1644  {
1645  m_operationsBetweenTimeChecks = DefaultOperationsBetweenTimeChecks;
1646 
1647  if (!IsTimeLimited)
1648  return;
1649 
1650  DateTime now = DateTime.Now;
1651  if (m_newGeneration.AccessedSinceLastTimeCheck)
1652  {
1653  // New generation has been accessed since last check
1654  // Update it's expiration time.
1655  m_newGeneration.ExpirationTime = now + ExpirationTime;
1656  m_newGeneration.AccessedSinceLastTimeCheck = false;
1657  }
1658  else if (m_newGeneration.ExpirationTime < now)
1659  {
1660  // New generation has been expired.
1661  // --> also old generation must be expired.
1662  PurgeGeneration(m_newGeneration);
1663  PurgeGeneration(m_oldGeneration);
1664  return;
1665  }
1666 
1667  if (m_oldGeneration.ExpirationTime < now)
1668  PurgeGeneration(m_oldGeneration);
1669  }
1670 
1685  public void Remove(TKey key)
1686  {
1687  if (key == null)
1688  throw new ArgumentNullException("key");
1689 
1690  int bucketIndex = GetBucketIndex(key);
1691  if (!m_newGeneration.Remove(bucketIndex, key))
1692  {
1693  if (!m_oldGeneration.Remove(bucketIndex, key))
1694  {
1695  CheckExpired();
1696  return;
1697  }
1698  }
1699 
1700  CheckExpired();
1701  m_version++;
1702  }
1703 
1718  public void RemoveRange(IEnumerable<TKey> keys)
1719  {
1720  if (keys == null)
1721  throw new ArgumentNullException("keys");
1722 
1723  foreach (TKey key in keys)
1724  {
1725  if (key == null)
1726  continue;
1727 
1728  int bucketIndex = GetBucketIndex(key);
1729  if (!m_newGeneration.Remove(bucketIndex, key))
1730  m_oldGeneration.Remove(bucketIndex, key);
1731  }
1732 
1733  CheckExpired();
1734  m_version++;
1735  }
1736 
1782  public bool Set(TKey key, TValue value, long size)
1783  {
1784  if (key == null)
1785  throw new ArgumentNullException("key");
1786 
1787  if (size < 0)
1788  throw new ArgumentOutOfRangeException("size", size, "Value's size can't be less than 0.");
1789 
1790  if (size > MaxElementSize)
1791  {
1792  // Entry size is too big to fit cache - ignore it
1793  Remove(key);
1794  return false;
1795  }
1796 
1797  if (size == 0)
1798  size = 1;
1799 
1800  int bucketIndex = GetBucketIndex(key);
1801  m_oldGeneration.Remove(bucketIndex, key);
1802  AddToNewGeneration(bucketIndex, key, value, size);
1803  CheckExpired();
1804 
1805  return true;
1806  }
1807 
1831  public bool TryGetValue(TKey key, out TValue value)
1832  {
1833  if (key == null)
1834  throw new ArgumentNullException("key");
1835 
1836  int bucketIndex = GetBucketIndex(key);
1837  long size;
1838  if (m_newGeneration.TryGetValue(bucketIndex, key, out value, out size))
1839  {
1840  CheckExpired();
1841  return true;
1842  }
1843 
1844  if (m_oldGeneration.TryGetValue(bucketIndex, key, out value, out size))
1845  {
1846  // Move element to new generation
1847  AddToNewGeneration(bucketIndex, key, value, size);
1848  CheckExpired();
1849  return true;
1850  }
1851 
1852  CheckExpired();
1853  return false;
1854  }
1855 
1863  IEnumerator IEnumerable.GetEnumerator()
1864  {
1865  return GetEnumerator();
1866  }
1867 
1868  #endregion
1869  }
1870 }
bool Set(TKey key, TValue value, long size)
Add or replace an element with the provided key , value and size to ICnmCache{TKey,TValue}.
void PurgeExpired()
Purge expired elements from the ICnmCache{TKey,TValue}.
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
Definition: ICM_Api.cs:31
void Remove(TKey key)
Removes element associated with key from the ICnmCache{TKey,TValue}.
virtual void PurgeGeneration(IGeneration generation)
Purge generation from the cache.
CnmMemoryCache(long maximalSize, int maximalCount, TimeSpan expirationTime, IEqualityComparer< TKey > comparer)
Initializes a new instance of the CnmMemoryCache{TKey,TValue} class.
IEnumerator< KeyValuePair< TKey, TValue > > GetEnumerator()
Returns an enumerator that iterates through the elements stored to CnmMemoryCache{TKey,TValue}.
void Clear()
Removes all elements from the ICnmCache{TKey,TValue}.
CnmMemoryCache()
Initializes a new instance of the CnmMemoryCache{TKey,TValue} class.
CnmMemoryCache(long maximalSize, int maximalCount, TimeSpan expirationTime)
Initializes a new instance of the CnmMemoryCache{TKey,TValue} class.
readonly IEqualityComparer< TKey > Comparer
Comparer used to compare element keys.
void RemoveRange(IEnumerable< TKey > keys)
Removes elements that are associated with one of keys from the ICnmCache{TKey,TValue}.
System.Collections.IEnumerable IEnumerable
CnmMemoryCache(long maximalSize, int maximalCount)
Initializes a new instance of the CnmMemoryCache{TKey,TValue} class.
bool TryGetValue(TKey key, out TValue value)
Gets the value associated with the specified key .
CnmMemoryCache(long maximalSize)
Initializes a new instance of the CnmMemoryCache{TKey,TValue} class.
virtual void AddToNewGeneration(int bucketIndex, TKey key, TValue value, long size)
Add element to new generation.