From cd3762ca9f97052a6fe91a3eca491407cc6f039e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 20 Oct 2012 01:26:04 +0100 Subject: Add experimental [Groups] MessageOnlineUsersOnly option for Flotsam XmlRpc groups. This retrieves and caches information from the PresenceService to only send messages to online users. This is reported to much improve performance for large groups where most users are offline. Cache is 20 seconds to balance requests against users not receiving messages until cache updates. This is an alternative to an approach where login/logout notification is sent directly from simulator to groups service. However, I'm not convinced that this PresenceService approach is actually better. Needs more thought. --- .../Avatar/XmlRpcGroups/GroupsMessagingModule.cs | 76 ++++++++++++++++++++-- 1 file changed, 69 insertions(+), 7 deletions(-) (limited to 'OpenSim') diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs index 10b83e6..55bb7dc 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using log4net; using Mono.Addins; @@ -36,6 +37,8 @@ using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups { @@ -45,6 +48,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private List m_sceneList = new List(); + private IPresenceService m_presenceService; private IMessageTransferModule m_msgTransferModule = null; @@ -54,6 +58,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups private bool m_groupMessagingEnabled = false; private bool m_debugEnabled = true; + /// + /// If enabled, module only tries to send group IMs to online users by querying cached presence information. + /// + private bool m_messageOnlineAgentsOnly; + + /// + /// Cache for online users. + /// + /// + /// Group ID is key, presence information for online members is value. + /// Will only be non-null if m_messageOnlineAgentsOnly = true + /// We cache here so that group messages don't constantly have to re-request the online user list to avoid + /// attempted expensive sending of messages to offline users. + /// The tradeoff is that a user that comes online will not receive messages consistently from all other users + /// until caches have updated. + /// Therefore, we set the cache expiry to just 20 seconds. + /// + private ExpiringCache m_usersOnlineCache; + + private int m_usersOnlineCacheExpirySeconds = 20; + #region IRegionModuleBase Members public void Initialise(IConfigSource config) @@ -83,10 +108,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups return; } + m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false); + + if (m_messageOnlineAgentsOnly) + m_usersOnlineCache = new ExpiringCache(); + m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true); } - m_log.Info("[GROUPS-MESSAGING]: GroupsMessagingModule starting up"); + m_log.InfoFormat( + "[GROUPS-MESSAGING]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}", + m_messageOnlineAgentsOnly, m_debugEnabled); } public void AddRegion(Scene scene) @@ -126,6 +158,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups return; } + if (m_presenceService == null) + m_presenceService = scene.PresenceService; m_sceneList.Add(scene); @@ -207,12 +241,40 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups public void SendMessageToGroup(GridInstantMessage im, UUID groupID) { List groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID); - - if (m_debugEnabled) - m_log.DebugFormat( - "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members", - groupID, groupMembers.Count); - + + if (m_messageOnlineAgentsOnly) + { + string[] t1 = groupMembers.ConvertAll(gmd => gmd.AgentID.ToString()).ToArray(); + + // We cache in order not to overwhlem the presence service on large grids with many groups. This does + // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed. + // (assuming this is the same across all grid simulators). + PresenceInfo[] onlineAgents; + if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents)) + { + onlineAgents = m_presenceService.GetAgents(t1); + m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); + } + + HashSet onlineAgentsUuidSet = new HashSet(); + Array.ForEach(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); + + int allMembersCount = groupMembers.Count; + groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); + + // if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members, {2} online", + groupID, allMembersCount, groupMembers.Count()); + } + else + { + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members", + groupID, groupMembers.Count); + } + foreach (GroupMembersData member in groupMembers) { if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID)) -- cgit v1.1