diff options
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.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs | 71 |
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; | |||
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Collections.Specialized; | 31 | using System.Collections.Specialized; |
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using System.Threading; | ||
33 | 34 | ||
34 | using Nwc.XmlRpc; | 35 | using 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 | ||