PageRenderTime 105ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/MalApi/AnimeListCache.cs

https://bitbucket.org/LHCGreg/mal-api
C# | 146 lines | 106 code | 18 blank | 22 comment | 12 complexity | 5404cddf01f986bd86d5fe7c3e3fefe9 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. namespace MalApi
  7. {
  8. /// <summary>
  9. /// Thread-safe cache with an optional expiration time. If the expiration time is null, anime lists are cached for the lifetime of
  10. /// the object. Expired cache entries are only actually removed when a new anime list is inserted into the cache. Cache expiration
  11. /// measurement is susceptible to changes to the system clock.
  12. /// </summary>
  13. internal class AnimeListCache : IDisposable
  14. {
  15. private Dictionary<string, MalUserLookupResults> m_animeListCache =
  16. new Dictionary<string, MalUserLookupResults>(StringComparer.InvariantCultureIgnoreCase);
  17. private LinkedList<Tuple<string, DateTime>> m_cachePutTimesSortedByTime;
  18. private Dictionary<string, LinkedListNode<Tuple<string, DateTime>>> m_cachePutTimesByName;
  19. private TimeSpan? m_expiration;
  20. private ReaderWriterLockSlim m_cacheLock = new ReaderWriterLockSlim();
  21. public AnimeListCache(TimeSpan? expiration)
  22. {
  23. m_expiration = expiration;
  24. if (m_expiration != null)
  25. {
  26. m_cachePutTimesSortedByTime = new LinkedList<Tuple<string, DateTime>>();
  27. m_cachePutTimesByName = new Dictionary<string, LinkedListNode<Tuple<string, DateTime>>>(StringComparer.InvariantCultureIgnoreCase);
  28. }
  29. }
  30. public bool GetListForUser(string user, out MalUserLookupResults animeList)
  31. {
  32. m_cacheLock.EnterReadLock();
  33. try
  34. {
  35. if (m_expiration == null)
  36. {
  37. if (m_animeListCache.TryGetValue(user, out animeList))
  38. {
  39. return true;
  40. }
  41. else
  42. {
  43. animeList = null;
  44. return false;
  45. }
  46. }
  47. LinkedListNode<Tuple<string, DateTime>> userAndTimeInsertedNode;
  48. // Check if this user is in the cache and if the cache entry is not stale
  49. if (m_cachePutTimesByName.TryGetValue(user, out userAndTimeInsertedNode))
  50. {
  51. DateTime expirationTime = userAndTimeInsertedNode.Value.Item2 + m_expiration.Value;
  52. if (DateTime.UtcNow < expirationTime)
  53. {
  54. animeList = m_animeListCache[user];
  55. return true;
  56. }
  57. else
  58. {
  59. animeList = null;
  60. return false;
  61. }
  62. }
  63. else
  64. {
  65. animeList = null;
  66. return false;
  67. }
  68. }
  69. finally
  70. {
  71. m_cacheLock.ExitReadLock();
  72. }
  73. }
  74. public void PutListForUser(string user, MalUserLookupResults animeList)
  75. {
  76. m_cacheLock.EnterWriteLock();
  77. try
  78. {
  79. if (m_expiration == null)
  80. {
  81. m_animeListCache[user] = animeList;
  82. return;
  83. }
  84. LinkedListNode<Tuple<string, DateTime>> nodeForLastInsert;
  85. if (m_cachePutTimesByName.TryGetValue(user, out nodeForLastInsert))
  86. {
  87. m_cachePutTimesSortedByTime.Remove(nodeForLastInsert);
  88. }
  89. DateTime nowUtc = DateTime.UtcNow;
  90. DateTime deleteOlderThan = nowUtc - m_expiration.Value;
  91. var newNode = m_cachePutTimesSortedByTime.AddFirst(new Tuple<string, DateTime>(user, nowUtc));
  92. m_cachePutTimesByName[user] = newNode;
  93. m_animeListCache[user] = animeList;
  94. // Check for old entries and remove them
  95. while (m_cachePutTimesSortedByTime.Count > 0 && m_cachePutTimesSortedByTime.Last.Value.Item2 < deleteOlderThan)
  96. {
  97. string oldUser = m_cachePutTimesSortedByTime.Last.Value.Item1;
  98. m_animeListCache.Remove(oldUser);
  99. m_cachePutTimesByName.Remove(oldUser);
  100. m_cachePutTimesSortedByTime.RemoveLast();
  101. }
  102. }
  103. finally
  104. {
  105. m_cacheLock.ExitWriteLock();
  106. }
  107. }
  108. public void Dispose()
  109. {
  110. m_cacheLock.Dispose();
  111. }
  112. }
  113. }
  114. /*
  115. Copyright 2011 Greg Najda
  116. Licensed under the Apache License, Version 2.0 (the "License");
  117. you may not use this file except in compliance with the License.
  118. You may obtain a copy of the License at
  119. http://www.apache.org/licenses/LICENSE-2.0
  120. Unless required by applicable law or agreed to in writing, software
  121. distributed under the License is distributed on an "AS IS" BASIS,
  122. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  123. See the License for the specific language governing permissions and
  124. limitations under the License.
  125. */