HG UAS: Moved hg-session data from memory to DB storage. This makes it so that traveling info survives Robust resets. It should also eliminate the cause of empty IP addresses in agent circuit data that we saw in CC grid. MySQL only.

cpu-performance
Diva Canto 2013-07-14 14:31:20 -07:00
parent 5939529036
commit e33ac50388
5 changed files with 344 additions and 90 deletions

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenSim.Framework;
namespace OpenSim.Data
{
// This MUST be a ref type!
public class HGTravelingData
{
public UUID SessionID;
public UUID UserID;
public Dictionary<string, string> Data;
public HGTravelingData()
{
Data = new Dictionary<string, string>();
}
}
/// <summary>
/// An interface for connecting to the user grid datastore
/// </summary>
public interface IHGTravelingData
{
HGTravelingData Get(UUID sessionID);
HGTravelingData[] GetSessions(UUID userID);
bool Store(HGTravelingData data);
bool Delete(UUID sessionID);
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Threading;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using MySql.Data.MySqlClient;
namespace OpenSim.Data.MySQL
{
/// <summary>
/// A MySQL Interface for user grid data
/// </summary>
public class MySQLHGTravelData : MySQLGenericTableHandler<HGTravelingData>, IHGTravelingData
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySQLHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") { }
public HGTravelingData Get(UUID sessionID)
{
HGTravelingData[] ret = Get("SessionID", sessionID.ToString());
if (ret.Length == 0)
return null;
return ret[0];
}
public HGTravelingData[] GetSessions(UUID userID)
{
return base.Get("UserID", userID.ToString());
}
public bool Delete(UUID sessionID)
{
return Delete("SessionID", sessionID.ToString());
}
}
}

View File

@ -0,0 +1,17 @@
:VERSION 1 # --------------------------
BEGIN;
CREATE TABLE `hg_traveling_data` (
`SessionID` VARCHAR(36) NOT NULL,
`UserID` VARCHAR(36) NOT NULL,
`GridExternalName` VARCHAR(255) NOT NULL DEFAULT '',
`ServiceToken` VARCHAR(255) NOT NULL DEFAULT '',
`ClientIPAddress` VARCHAR(16) NOT NULL DEFAULT '',
`MyIPAddress` VARCHAR(16) NOT NULL DEFAULT '',
PRIMARY KEY (`SessionID`),
KEY (`UserID`)
) ENGINE=InnoDB;
COMMIT;

View File

@ -30,6 +30,7 @@ using System.Collections.Generic;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using OpenSim.Data;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Services.Connectors.Friends; using OpenSim.Services.Connectors.Friends;
using OpenSim.Services.Connectors.Hypergrid; using OpenSim.Services.Connectors.Hypergrid;
@ -50,14 +51,14 @@ namespace OpenSim.Services.HypergridService
/// needs to do it for them. /// needs to do it for them.
/// Once we have better clients, this shouldn't be needed. /// Once we have better clients, this shouldn't be needed.
/// </summary> /// </summary>
public class UserAgentService : IUserAgentService public class UserAgentService : UserAgentServiceBase, IUserAgentService
{ {
private static readonly ILog m_log = private static readonly ILog m_log =
LogManager.GetLogger( LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType); MethodBase.GetCurrentMethod().DeclaringType);
// This will need to go into a DB table // This will need to go into a DB table
static Dictionary<UUID, TravelingAgentInfo> m_TravelingAgents = new Dictionary<UUID, TravelingAgentInfo>(); //static Dictionary<UUID, TravelingAgentInfo> m_Database = new Dictionary<UUID, TravelingAgentInfo>();
static bool m_Initialized = false; static bool m_Initialized = false;
@ -86,6 +87,7 @@ namespace OpenSim.Services.HypergridService
} }
public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector) public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector)
: base(config)
{ {
// Let's set this always, because we don't know the sequence // Let's set this always, because we don't know the sequence
// of instantiations // of instantiations
@ -260,7 +262,8 @@ namespace OpenSim.Services.HypergridService
// Generate a new service session // Generate a new service session
agentCircuit.ServiceSessionID = region.ServerURI + ";" + UUID.Random(); agentCircuit.ServiceSessionID = region.ServerURI + ";" + UUID.Random();
TravelingAgentInfo old = UpdateTravelInfo(agentCircuit, region); TravelingAgentInfo old = null;
TravelingAgentInfo travel = CreateTravelInfo(agentCircuit, region, fromLogin, out old);
bool success = false; bool success = false;
string myExternalIP = string.Empty; string myExternalIP = string.Empty;
@ -282,23 +285,21 @@ namespace OpenSim.Services.HypergridService
m_log.DebugFormat("[USER AGENT SERVICE]: Unable to login user {0} {1} to grid {2}, reason: {3}", m_log.DebugFormat("[USER AGENT SERVICE]: Unable to login user {0} {1} to grid {2}, reason: {3}",
agentCircuit.firstname, agentCircuit.lastname, region.ServerURI, reason); agentCircuit.firstname, agentCircuit.lastname, region.ServerURI, reason);
// restore the old travel info if (old != null)
lock (m_TravelingAgents) StoreTravelInfo(old);
{ else
if (old == null) m_Database.Delete(agentCircuit.SessionID);
m_TravelingAgents.Remove(agentCircuit.SessionID);
else
m_TravelingAgents[agentCircuit.SessionID] = old;
}
return false; return false;
} }
// Everything is ok
// Update the perceived IP Address of our grid
m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP);
// else set the IP addresses associated with this client travel.MyIpAddress = myExternalIP;
if (fromLogin)
m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = agentCircuit.IPAddress; StoreTravelInfo(travel);
m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP;
return true; return true;
} }
@ -309,57 +310,39 @@ namespace OpenSim.Services.HypergridService
return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, false, out reason); return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, false, out reason);
} }
private void SetClientIP(UUID sessionID, string ip) TravelingAgentInfo CreateTravelInfo(AgentCircuitData agentCircuit, GridRegion region, bool fromLogin, out TravelingAgentInfo existing)
{ {
if (m_TravelingAgents.ContainsKey(sessionID)) HGTravelingData hgt = m_Database.Get(agentCircuit.SessionID);
existing = null;
if (hgt != null)
{ {
m_log.DebugFormat("[USER AGENT SERVICE]: Setting IP {0} for session {1}", ip, sessionID); // Very important! Override whatever this agent comes with.
m_TravelingAgents[sessionID].ClientIPAddress = ip; // UserAgentService always sets the IP for every new agent
// with the original IP address.
existing = new TravelingAgentInfo(hgt);
agentCircuit.IPAddress = existing.ClientIPAddress;
} }
}
TravelingAgentInfo UpdateTravelInfo(AgentCircuitData agentCircuit, GridRegion region) TravelingAgentInfo travel = new TravelingAgentInfo(existing);
{ travel.SessionID = agentCircuit.SessionID;
TravelingAgentInfo travel = new TravelingAgentInfo();
TravelingAgentInfo old = null;
lock (m_TravelingAgents)
{
if (m_TravelingAgents.ContainsKey(agentCircuit.SessionID))
{
// Very important! Override whatever this agent comes with.
// UserAgentService always sets the IP for every new agent
// with the original IP address.
agentCircuit.IPAddress = m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress;
old = m_TravelingAgents[agentCircuit.SessionID];
}
m_TravelingAgents[agentCircuit.SessionID] = travel;
}
travel.UserID = agentCircuit.AgentID; travel.UserID = agentCircuit.AgentID;
travel.GridExternalName = region.ServerURI; travel.GridExternalName = region.ServerURI;
travel.ServiceToken = agentCircuit.ServiceSessionID; travel.ServiceToken = agentCircuit.ServiceSessionID;
if (old != null)
travel.ClientIPAddress = old.ClientIPAddress;
return old; if (fromLogin)
travel.ClientIPAddress = agentCircuit.IPAddress;
StoreTravelInfo(travel);
return travel;
} }
public void LogoutAgent(UUID userID, UUID sessionID) public void LogoutAgent(UUID userID, UUID sessionID)
{ {
m_log.DebugFormat("[USER AGENT SERVICE]: User {0} logged out", userID); m_log.DebugFormat("[USER AGENT SERVICE]: User {0} logged out", userID);
lock (m_TravelingAgents) m_Database.Delete(sessionID);
{
List<UUID> travels = new List<UUID>();
foreach (KeyValuePair<UUID, TravelingAgentInfo> kvp in m_TravelingAgents)
if (kvp.Value == null) // do some clean up
travels.Add(kvp.Key);
else if (kvp.Value.UserID == userID)
travels.Add(kvp.Key);
foreach (UUID session in travels)
m_TravelingAgents.Remove(session);
}
GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(userID.ToString()); GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(userID.ToString());
if (guinfo != null) if (guinfo != null)
@ -369,10 +352,11 @@ namespace OpenSim.Services.HypergridService
// We need to prevent foreign users with the same UUID as a local user // We need to prevent foreign users with the same UUID as a local user
public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName) public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName)
{ {
if (!m_TravelingAgents.ContainsKey(sessionID)) HGTravelingData hgt = m_Database.Get(sessionID);
if (hgt == null)
return false; return false;
TravelingAgentInfo travel = m_TravelingAgents[sessionID]; TravelingAgentInfo travel = new TravelingAgentInfo(hgt);
return travel.GridExternalName.ToLower() == thisGridExternalName.ToLower(); return travel.GridExternalName.ToLower() == thisGridExternalName.ToLower();
} }
@ -385,31 +369,32 @@ namespace OpenSim.Services.HypergridService
m_log.DebugFormat("[USER AGENT SERVICE]: Verifying Client session {0} with reported IP {1}.", m_log.DebugFormat("[USER AGENT SERVICE]: Verifying Client session {0} with reported IP {1}.",
sessionID, reportedIP); sessionID, reportedIP);
if (m_TravelingAgents.ContainsKey(sessionID)) HGTravelingData hgt = m_Database.Get(sessionID);
{ if (hgt == null)
bool result = m_TravelingAgents[sessionID].ClientIPAddress == reportedIP || return false;
m_TravelingAgents[sessionID].MyIpAddress == reportedIP; // NATed
m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}", TravelingAgentInfo travel = new TravelingAgentInfo(hgt);
reportedIP, m_TravelingAgents[sessionID].ClientIPAddress, m_TravelingAgents[sessionID].MyIpAddress, result);
return result; bool result = travel.ClientIPAddress == reportedIP || travel.MyIpAddress == reportedIP; // NATed
}
return false; m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}",
reportedIP, travel.ClientIPAddress, travel.MyIpAddress, result);
return result;
} }
public bool VerifyAgent(UUID sessionID, string token) public bool VerifyAgent(UUID sessionID, string token)
{ {
if (m_TravelingAgents.ContainsKey(sessionID)) HGTravelingData hgt = m_Database.Get(sessionID);
if (hgt == null)
{ {
m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, m_TravelingAgents[sessionID].ServiceToken); m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID);
return m_TravelingAgents[sessionID].ServiceToken == token; return false;
} }
m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID); TravelingAgentInfo travel = new TravelingAgentInfo(hgt);
m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, travel.ServiceToken);
return false; return travel.ServiceToken == token;
} }
[Obsolete] [Obsolete]
@ -472,17 +457,17 @@ namespace OpenSim.Services.HypergridService
} }
} }
// Lastly, let's notify the rest who may be online somewhere else //// Lastly, let's notify the rest who may be online somewhere else
foreach (string user in usersToBeNotified) //foreach (string user in usersToBeNotified)
{ //{
UUID id = new UUID(user); // UUID id = new UUID(user);
if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) // if (m_Database.ContainsKey(id) && m_Database[id].GridExternalName != m_GridName)
{ // {
string url = m_TravelingAgents[id].GridExternalName; // string url = m_Database[id].GridExternalName;
// forward // // forward
m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url); // m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url);
} // }
} //}
// and finally, let's send the online friends // and finally, let's send the online friends
if (online) if (online)
@ -609,16 +594,13 @@ namespace OpenSim.Services.HypergridService
public string LocateUser(UUID userID) public string LocateUser(UUID userID)
{ {
foreach (TravelingAgentInfo t in m_TravelingAgents.Values) HGTravelingData[] hgts = m_Database.GetSessions(userID);
{ if (hgts == null)
if (t == null) return string.Empty;
{
m_log.ErrorFormat("[USER AGENT SERVICE]: Oops! Null TravelingAgentInfo. Please report this on mantis"); foreach (HGTravelingData t in hgts)
continue; if (t.Data.ContainsKey("GridExternalName") && !m_GridName.Equals(t.Data["GridExternalName"]))
} return t.Data["GridExternalName"];
if (t.UserID == userID && !m_GridName.Equals(t.GridExternalName))
return t.GridExternalName;
}
return string.Empty; return string.Empty;
} }
@ -689,17 +671,60 @@ namespace OpenSim.Services.HypergridService
return exception; return exception;
} }
private void StoreTravelInfo(TravelingAgentInfo travel)
{
if (travel == null)
return;
HGTravelingData hgt = new HGTravelingData();
hgt.SessionID = travel.SessionID;
hgt.UserID = travel.UserID;
hgt.Data = new Dictionary<string, string>();
hgt.Data["GridExternalName"] = travel.GridExternalName;
hgt.Data["ServiceToken"] = travel.ServiceToken;
hgt.Data["ClientIPAddress"] = travel.ClientIPAddress;
hgt.Data["MyIPAddress"] = travel.MyIpAddress;
m_Database.Store(hgt);
}
#endregion #endregion
} }
class TravelingAgentInfo class TravelingAgentInfo
{ {
public UUID SessionID;
public UUID UserID; public UUID UserID;
public string GridExternalName = string.Empty; public string GridExternalName = string.Empty;
public string ServiceToken = string.Empty; public string ServiceToken = string.Empty;
public string ClientIPAddress = string.Empty; // as seen from this user agent service public string ClientIPAddress = string.Empty; // as seen from this user agent service
public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper
public TravelingAgentInfo(HGTravelingData t)
{
if (t.Data != null)
{
SessionID = new UUID(t.SessionID);
UserID = new UUID(t.UserID);
GridExternalName = t.Data["GridExternalName"];
ServiceToken = t.Data["ServiceToken"];
ClientIPAddress = t.Data["ClientIPAddress"];
MyIpAddress = t.Data["MyIPAddress"];
}
}
public TravelingAgentInfo(TravelingAgentInfo old)
{
if (old != null)
{
SessionID = old.SessionID;
UserID = old.UserID;
GridExternalName = old.GridExternalName;
ServiceToken = old.ServiceToken;
ClientIPAddress = old.ClientIPAddress;
MyIpAddress = old.MyIpAddress;
}
}
} }
} }

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Reflection;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Data;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Base;
namespace OpenSim.Services.HypergridService
{
public class UserAgentServiceBase : ServiceBase
{
protected IHGTravelingData m_Database = null;
public UserAgentServiceBase(IConfigSource config)
: base(config)
{
string dllName = String.Empty;
string connString = String.Empty;
string realm = "hg_traveling_data";
//
// Try reading the [DatabaseService] section, if it exists
//
IConfig dbConfig = config.Configs["DatabaseService"];
if (dbConfig != null)
{
if (dllName == String.Empty)
dllName = dbConfig.GetString("StorageProvider", String.Empty);
if (connString == String.Empty)
connString = dbConfig.GetString("ConnectionString", String.Empty);
}
//
// [UserAgentService] section overrides [DatabaseService], if it exists
//
IConfig gridConfig = config.Configs["UserAgentService"];
if (gridConfig != null)
{
dllName = gridConfig.GetString("StorageProvider", dllName);
connString = gridConfig.GetString("ConnectionString", connString);
realm = gridConfig.GetString("Realm", realm);
}
//
// We tried, but this doesn't exist. We can't proceed.
//
if (dllName.Equals(String.Empty))
throw new Exception("No StorageProvider configured");
m_Database = LoadPlugin<IHGTravelingData>(dllName, new Object[] { connString, realm });
if (m_Database == null)
throw new Exception("Could not find a storage interface in the given module");
}
}
}