[Fix] Bugzilla #18245 - System.Runtime.MemoryCache.GetValues() throws LockRecursionEx...
authorCraig Minihan <v-craig.minihan@exony.com>
Fri, 7 Mar 2014 12:40:23 +0000 (04:40 -0800)
committerCraig Minihan <v-craig.minihan@exony.com>
Fri, 7 Mar 2014 12:40:23 +0000 (04:40 -0800)
- GetValues() calls MemoryCacheContainer.GetEntry() which now gets an EnterUpgradeableReadLock needed by ExpireIfNeeded()
- Added a test case

mcs/class/System.Runtime.Caching/System.Runtime.Caching/MemoryCacheContainer.cs
mcs/class/System.Runtime.Caching/Test/System.Runtime.Caching/MemoryCacheTest.cs

index 43de07dcbb7b5cf2b184d787d69134965c78c921..a728e0c1102f04ce4fb73da7a5f2f1e24d6bb4f6 100644 (file)
@@ -265,10 +265,10 @@ namespace System.Runtime.Caching
 
                public MemoryCacheEntry GetEntry (string key)
                {
-                       bool locked = false;
+                       bool readLocked = false;
                        try {
-                               cache_lock.EnterReadLock ();
-                               locked = true;
+                               cache_lock.EnterUpgradeableReadLock ();
+                               readLocked = true;
 
                                MemoryCacheEntry entry;
                                if (cache.TryGetValue (key, out entry)) {
@@ -280,8 +280,8 @@ namespace System.Runtime.Caching
                                
                                return null;
                        } finally {
-                               if (locked)
-                                       cache_lock.ExitReadLock ();
+                               if (readLocked)
+                                       cache_lock.ExitUpgradeableReadLock ();
                        }
                }
                
index 02cbfcb86a4ad165375e6916e7d1dc5e98e3203c..eecec7315cdfd9fd371d5e30a3f2eba1493f3a89 100644 (file)
@@ -1281,5 +1281,45 @@ namespace MonoTests.System.Runtime.Caching
                                Assert.AreEqual (HEAP_RESIZE_LONG_ENTRIES + HEAP_RESIZE_LONG_ENTRIES, mc.GetCount (), "#CS5");  
                        }
                }
+
+               [Test]
+               public void TestExpiredGetValues ()
+               {
+                       var config = new NameValueCollection ();
+                       config["cacheMemoryLimitMegabytes"] = 0.ToString ();
+                       config["physicalMemoryLimitPercentage"] = 100.ToString ();
+                       config["__MonoEmulateOneCPU"] = true.ToString ();
+
+                       // it appears that pollingInterval does nothing, so we set the Mono timer as well
+                       config["pollingInterval"] = new TimeSpan (0, 0, 10).ToString ();
+                       config["__MonoTimerPeriod"] = 10.ToString ();
+                       
+                       using (var mc = new MemoryCache ("TestExpiredGetValues",  config)) {
+                               Assert.AreEqual (0, mc.GetCount (), "#EGV1");
+
+                               var keys = new List<string> ();
+
+                               // add some short duration entries
+                               for (int i = 0; i < 10; i++) {
+                                       var key = "short-" + i;
+                                       var expireAt = DateTimeOffset.Now.AddSeconds (1);
+                                       mc.Add (key, i.ToString (), expireAt);
+
+                                       keys.Add (key);
+                               }
+
+                               Assert.AreEqual (10, mc.GetCount (), "#EGV2");
+
+                               global::System.Threading.Thread.Sleep (1000);
+
+                               // we have waited but the items won't be expired by the timer since it wont have fired yet
+                               Assert.AreEqual (10, mc.GetCount (), "#EGV3");
+
+                               // calling GetValues() will expire the items since we are now past their expiresAt
+                               mc.GetValues (keys);
+
+                               Assert.AreEqual (0, mc.GetCount (), "#EGV4");
+                       }
+               }
        }
 }