aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMic Bowman2012-02-13 19:38:22 -0800
committerMic Bowman2012-02-13 19:38:22 -0800
commita9e8bd59a377e7c7ce81e3693875467926dd7d4b (patch)
tree6420f1f0488024f0b9ea0d7ff36c51e42f9d98be
parentFix: get embedded objects from Notecard fails with activated FreeSwitchVoiceM... (diff)
downloadopensim-SC-a9e8bd59a377e7c7ce81e3693875467926dd7d4b.zip
opensim-SC-a9e8bd59a377e7c7ce81e3693875467926dd7d4b.tar.gz
opensim-SC-a9e8bd59a377e7c7ce81e3693875467926dd7d4b.tar.bz2
opensim-SC-a9e8bd59a377e7c7ce81e3693875467926dd7d4b.tar.xz
Fix a race condition in the simian groups connector. When requests were
too slow they would circumvent the cache (piling up on the network service and making the problem even worse). This condition happens frequently during permission checks.
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs71
1 files changed, 63 insertions, 8 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
index 42008da..130513d 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
@@ -30,6 +30,7 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Collections.Specialized; 31using System.Collections.Specialized;
32using System.Reflection; 32using System.Reflection;
33using System.Threading;
33 34
34using Nwc.XmlRpc; 35using Nwc.XmlRpc;
35 36
@@ -167,6 +168,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
167 168
168 private bool m_debugEnabled = false; 169 private bool m_debugEnabled = false;
169 170
171 private Dictionary<string, bool> m_pendingRequests = new Dictionary<string,bool>();
172
170 private ExpiringCache<string, OSDMap> m_memoryCache; 173 private ExpiringCache<string, OSDMap> m_memoryCache;
171 private int m_cacheTimeout = 30; 174 private int m_cacheTimeout = 30;
172 175
@@ -1348,6 +1351,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1348 // Immediately forward the request if the cache is disabled. 1351 // Immediately forward the request if the cache is disabled.
1349 if (m_cacheTimeout == 0) 1352 if (m_cacheTimeout == 0)
1350 { 1353 {
1354 m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: cache is disabled");
1351 return WebUtil.PostToService(m_groupsServerURI, requestArgs); 1355 return WebUtil.PostToService(m_groupsServerURI, requestArgs);
1352 } 1356 }
1353 1357
@@ -1355,6 +1359,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1355 if (requestArgs["RequestMethod"] == "RemoveGeneric" 1359 if (requestArgs["RequestMethod"] == "RemoveGeneric"
1356 || requestArgs["RequestMethod"] == "AddGeneric") 1360 || requestArgs["RequestMethod"] == "AddGeneric")
1357 { 1361 {
1362 m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: clearing generics cache");
1363
1358 // Any and all updates cause the cache to clear 1364 // Any and all updates cause the cache to clear
1359 m_memoryCache.Clear(); 1365 m_memoryCache.Clear();
1360 1366
@@ -1366,18 +1372,67 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1366 1372
1367 // Create the cache key for the request and see if we have it cached 1373 // Create the cache key for the request and see if we have it cached
1368 string CacheKey = WebUtil.BuildQueryString(requestArgs); 1374 string CacheKey = WebUtil.BuildQueryString(requestArgs);
1369 OSDMap response = null; 1375
1370 if (!m_memoryCache.TryGetValue(CacheKey, out response)) 1376 // This code uses a leader/follower pattern. On a cache miss, the request is added
1377 // to a queue; the first thread to add it to the queue completes the request while
1378 // follow on threads busy wait for the results, this situation seems to happen
1379 // often when checking permissions
1380 while (true)
1371 { 1381 {
1372 // if it wasn't in the cache, pass the request to the Simian Grid Services 1382 OSDMap response = null;
1373 response = WebUtil.PostToService(m_groupsServerURI, requestArgs); 1383 bool firstRequest = false;
1374 1384
1375 // and cache the response 1385 lock (m_memoryCache)
1376 m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout)); 1386 {
1387 if (m_memoryCache.TryGetValue(CacheKey, out response))
1388 return response;
1389
1390 if (! m_pendingRequests.ContainsKey(CacheKey))
1391 {
1392 m_pendingRequests.Add(CacheKey,true);
1393 firstRequest = true;
1394 }
1395 }
1396
1397 if (firstRequest)
1398 {
1399 // if it wasn't in the cache, pass the request to the Simian Grid Services
1400 try
1401 {
1402 response = WebUtil.PostToService(m_groupsServerURI, requestArgs);
1403 }
1404 catch (Exception e)
1405 {
1406 m_log.InfoFormat("[SIMIAN GROUPS CONNECTOR] request failed {0}",CacheKey);
1407 }
1408
1409 // and cache the response
1410 lock (m_memoryCache)
1411 {
1412 m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout));
1413 m_pendingRequests.Remove(CacheKey);
1414 }
1415
1416 return response;
1417 }
1418
1419 Thread.Sleep(50); // waiting for a web request to complete, 50msecs is reasonable
1377 } 1420 }
1378 1421
1379 // return cached response 1422 // if (!m_memoryCache.TryGetValue(CacheKey, out response))
1380 return response; 1423 // {
1424 // m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: query not in the cache");
1425 // Util.PrintCallStack();
1426
1427 // // if it wasn't in the cache, pass the request to the Simian Grid Services
1428 // response = WebUtil.PostToService(m_groupsServerURI, requestArgs);
1429
1430 // // and cache the response
1431 // m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout));
1432 // }
1433
1434 // // return cached response
1435 // return response;
1381 } 1436 }
1382 #endregion 1437 #endregion
1383 1438