2011-06-17 22:20:35 +00:00
/ *
* Copyright ( c ) Contributors , http : //opensimulator.org/
* See CONTRIBUTORS . TXT for a full list of copyright holders .
*
2011-03-18 20:59:33 +00:00
* 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 .
2011-06-17 22:20:35 +00:00
* * Redistributions in binary form must reproduce the above copyrightD
2011-03-18 20:59:33 +00:00
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2011-06-17 22:20:35 +00:00
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
2011-03-18 20:59:33 +00:00
* 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 ;
2011-02-26 00:30:52 +00:00
using System.IO ;
using System.Net ;
using System.Net.Sockets ;
using System.Text ;
using System.Collections.Generic ;
using System.Threading ;
using OpenSim.Framework ;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander ;
using OpenSim.Region.Framework.Scenes ;
using OpenSim.Region.Framework.Interfaces ;
using log4net ;
using OpenMetaverse ;
using OpenMetaverse.StructuredData ;
using OpenSim.Region.Framework.Scenes.Serialization ;
using OpenSim.Region.Physics.Manager ;
namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{
//Information of a registered idle physics engine.
//Note, this is a temporary solution to inlcude idle physics engines here.
//In the future, there might be a independent load balaner that keeps track
//of available idle hardware.
public class IdlePhysEngineInfo
{
public TcpClient TClient ;
//public IPAddress PhysEngineIPAddr;
//public int PhysEnginePort;
public string ID ;
//Will be used to store the overloaded PE that has send LB request and paired with this idle PE
public SceneToPhysEngineConnector AwaitOverloadedSE = null ;
public IdlePhysEngineInfo ( TcpClient tclient )
{
if ( tclient = = null ) return ;
TClient = tclient ;
IPAddress ipAddr = ( ( IPEndPoint ) tclient . Client . RemoteEndPoint ) . Address ;
int port = ( ( IPEndPoint ) tclient . Client . RemoteEndPoint ) . Port ;
ID = ipAddr . ToString ( ) + ":" + port ;
}
}
//Here is the per actor type listening server for physics Engines.
public class SceneToPhysEngineSyncServer : ISceneToPhysEngineServer , ICommandableModule
{
#region SceneToPhysEngineSyncServer members
// Set the addr and port for TcpListener
private IPAddress m_addr ;
private Int32 m_port ;
//this field is only meaning for the QuarkInfo records on the Scene side
private SceneToPhysEngineConnector m_peConnector = null ;
public SceneToPhysEngineConnector PEConnector
{
get { return m_peConnector ; }
set { m_peConnector = value ; }
}
private int peCounter ;
// static counters that are used to compute global configuration state
private static int m_syncServerInitialized = 0 ;
private static int m_totalConnections = 0 ;
private static List < Scene > m_allScenes = new List < Scene > ( ) ;
// The local scene.
private Scene m_scene ;
private ILog m_log ;
// The listener and the thread which listens for connections from client managers
private TcpListener m_listener ;
private Thread m_listenerThread ;
private object m_physEngineConnector_lock = new object ( ) ;
//private Dictionary<string, SceneToPhysEngineConnector> m_physEngineConnectors = new Dictionary<string, SceneToPhysEngineConnector>();
private List < SceneToPhysEngineConnector > m_physEngineConnectors = new List < SceneToPhysEngineConnector > ( ) ;
// the last connector created
private SceneToPhysEngineConnector m_sceneToPhysEngineConnector = null ;
//list of idle physics engines that have registered.
private List < IdlePhysEngineInfo > m_idlePhysEngineList = new List < IdlePhysEngineInfo > ( ) ;
private string LogHeader = "[SCENE TO PHYS ENGINE SYNC SERVER]" ;
#region ICommandableModule Members
private readonly Commander m_commander = new Commander ( "phys" ) ;
public ICommander CommandInterface
{
get { return m_commander ; }
}
private void InstallInterfaces ( )
{
// Command cmdSyncStart = new Command("start", CommandIntentions.COMMAND_HAZARDOUS, SyncStart, "Begins synchronization with RegionSyncServer.");
//cmdSyncStart.AddArgument("server_port", "The port of the server to synchronize with", "Integer");
// Command cmdSyncStop = new Command("stop", CommandIntentions.COMMAND_HAZARDOUS, SyncStop, "Stops synchronization with RegionSyncServer.");
//cmdSyncStop.AddArgument("server_address", "The IP address of the server to synchronize with", "String");
//cmdSyncStop.AddArgument("server_port", "The port of the server to synchronize with", "Integer");
Command cmdSyncStatus = new Command ( "status" , CommandIntentions . COMMAND_HAZARDOUS , SyncStatus , "Displays synchronization status." ) ;
// m_commander.RegisterCommand("start", cmdSyncStart);
// m_commander.RegisterCommand("stop", cmdSyncStop);
m_commander . RegisterCommand ( "status" , cmdSyncStatus ) ;
lock ( m_scene )
{
// Add this to our scene so scripts can call these functions
m_scene . RegisterModuleCommander ( m_commander ) ;
}
}
/// <summary>
/// Processes commandline input. Do not call directly.
/// </summary>
/// <param name="args">Commandline arguments</param>
private void EventManager_OnPluginConsole ( string [ ] args )
{
if ( args [ 0 ] = = "phys" )
{
if ( args . Length = = 1 )
{
m_commander . ProcessConsoleCommand ( "help" , new string [ 0 ] ) ;
return ;
}
string [ ] tmpArgs = new string [ args . Length - 2 ] ;
int i ;
for ( i = 2 ; i < args . Length ; i + + )
tmpArgs [ i - 2 ] = args [ i ] ;
m_commander . ProcessConsoleCommand ( args [ 1 ] , tmpArgs ) ;
}
}
private void SyncStart ( Object [ ] args )
{
return ;
}
private void SyncStop ( Object [ ] args )
{
return ;
}
private void SyncStatus ( Object [ ] args )
{
lock ( m_physEngineConnector_lock )
{
if ( m_physEngineConnectors . Count = = 0 )
{
m_log . Warn ( LogHeader + " Not currently synchronized" ) ;
return ;
}
m_log . Warn ( LogHeader + " Synchronized" ) ;
foreach ( SceneToPhysEngineConnector pec in m_physEngineConnectors )
{
2011-03-10 22:04:10 +00:00
m_log . Warn ( pec . StatisticLine ( true ) ) ;
2011-02-26 00:30:52 +00:00
}
}
}
# endregion
// Check if any of the client views are in a connected state
public bool IsPhysEngineScene ( ) { return SceneToPhysEngineSyncServer . IsPhysEngineScene2S ( ) ; }
public bool IsActivePhysEngineScene ( ) { return SceneToPhysEngineSyncServer . IsActivePhysEngineScene2S ( ) ; }
public bool IsPhysEngineActor ( ) { return SceneToPhysEngineSyncServer . IsPhysEngineActorS ; }
public bool Synced
{
get { return ( m_physEngineConnectors . Count > 0 ) ; }
}
public static bool IsPhysEngineSceneS
{
get { return ( SceneToPhysEngineSyncServer . m_syncServerInitialized > 0 ) ; }
}
public static bool IsPhysEngineScene2S ( )
{
return ( SceneToPhysEngineSyncServer . m_syncServerInitialized > 0 ) ;
}
public static bool IsActivePhysEngineSceneS
{
get {
System . Console . WriteLine ( "IsActivePhysEngineScene: si={0} tc={1}" ,
SceneToPhysEngineSyncServer . m_syncServerInitialized ,
SceneToPhysEngineSyncServer . m_totalConnections ) ;
return ( SceneToPhysEngineSyncServer . m_syncServerInitialized > 0
& & SceneToPhysEngineSyncServer . m_totalConnections > 0 ) ;
}
}
public static bool IsActivePhysEngineScene2S ( )
{
return ( SceneToPhysEngineSyncServer . m_syncServerInitialized > 0
& & SceneToPhysEngineSyncServer . m_totalConnections > 0 ) ;
}
public static bool IsPhysEngineActorS
{
get { return PhysEngineToSceneConnectorModule . IsPhysEngineActorS ; }
}
/// <summary>
/// The scene is unknown by ODE so we have to look through the scenes to
/// find the one with this PhysicsActor so we can send the update.
/// </summary>
/// <param name="pa"></param>
public static void RouteUpdate ( PhysicsActor pa )
{
SceneObjectPart sop = null ;
Scene s = null ;
foreach ( Scene ss in m_allScenes )
{
try
{
sop = ss . GetSceneObjectPart ( pa . UUID ) ;
}
catch
{
sop = null ;
}
if ( sop ! = null )
{
s = ss ;
break ;
}
else
{
ScenePresence sp = ss . GetScenePresence ( pa . UUID ) ;
if ( sp ! = null )
{
s = ss ;
break ;
}
}
}
if ( s ! = null )
{
if ( s . SceneToPhysEngineSyncServer ! = null )
{
s . SceneToPhysEngineSyncServer . SendUpdate ( pa ) ;
}
else
{
Console . WriteLine ( "RouteUpdate: SceneToPhysEngineSyncServer is not available" ) ;
}
}
else
{
Console . WriteLine ( "RouteUpdate: no SOP for update of {0}" , pa . UUID ) ;
}
return ;
}
public void SendUpdate ( PhysicsActor pa )
{
// m_log.DebugFormat("{0}: SendUpdate for {1}", LogHeader, pa.LocalID);
if ( m_sceneToPhysEngineConnector ! = null )
{
this . m_sceneToPhysEngineConnector . SendPhysUpdateAttributes ( pa ) ;
}
}
# endregion
// Constructor
public SceneToPhysEngineSyncServer ( Scene scene , string addr , int port )
{
m_log = LogManager . GetLogger ( System . Reflection . MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
//m_log.Warn(LogHeader + "Constructed");
m_scene = scene ;
m_addr = IPAddress . Parse ( addr ) ;
m_port = port ;
m_scene . RegisterModuleInterface < ISceneToPhysEngineServer > ( this ) ;
// remember all the scenes that are configured for connection to physics engine
if ( ! m_allScenes . Contains ( m_scene ) )
{
m_allScenes . Add ( m_scene ) ;
}
SubscribeToEvents ( ) ;
m_scene . EventManager . OnPluginConsole + = EventManager_OnPluginConsole ;
InstallInterfaces ( ) ;
}
private void SubscribeToEvents ( )
{
}
private void UnSubscribeToEvents ( )
{
}
// Start the server
public void Start ( )
{
SceneToPhysEngineSyncServer . m_syncServerInitialized + + ;
m_listenerThread = new Thread ( new ThreadStart ( Listen ) ) ;
m_listenerThread . Name = "SceneToPhysEngineSyncServer Listener" ;
m_log . DebugFormat ( "{0}: Starting {1} thread" , LogHeader , m_listenerThread . Name ) ;
m_listenerThread . Start ( ) ;
// m_log.DebugFormat("{0}: Started", LogHeader);
}
// Stop the server and disconnect all RegionSyncClients
public void Shutdown ( )
{
m_log . DebugFormat ( "{0}: Shutdown" , LogHeader ) ;
SceneToPhysEngineSyncServer . m_syncServerInitialized - - ;
// Stop the listener and listening thread so no new clients are accepted
m_listener . Stop ( ) ;
m_listenerThread . Abort ( ) ;
m_listenerThread = null ;
// Stop all existing SceneTOSEConnectors
//TO FINISH
foreach ( SceneToPhysEngineConnector peConnector in m_physEngineConnectors )
{
peConnector . Shutdown ( ) ;
}
m_physEngineConnectors . Clear ( ) ;
UnSubscribeToEvents ( ) ;
}
// Add a connector to a physics engine
public void AddSyncedPhysEngine ( SceneToPhysEngineConnector peConnector )
{
lock ( m_physEngineConnector_lock )
{
m_physEngineConnectors . Add ( peConnector ) ;
m_sceneToPhysEngineConnector = peConnector ;
}
}
// Remove the client view from the list and decrement synced client counter
public void RemoveSyncedPhysEngine ( SceneToPhysEngineConnector peConnector )
{
lock ( m_physEngineConnector_lock )
{
//Dictionary<string, SceneToPhysEngineConnector> currentlist = m_physEngineConnectors;
//Dictionary<string, SceneToPhysEngineConnector> newlist = new Dictionary<string, SceneToPhysEngineConnector>(currentlist);
m_physEngineConnectors . Remove ( peConnector ) ;
// Threads holding the previous version of the list can keep using it since
// they will not hold it for long and get a new copy next time they need to iterate
//m_physEngineConnectors = newlist;
}
}
// Listen for connections from a new RegionSyncClient
// When connected, start the ReceiveLoop for the new client
private void Listen ( )
{
m_listener = new TcpListener ( m_addr , m_port ) ;
try
{
// Start listening for clients
m_listener . Start ( ) ;
while ( true )
{
// *** Move/Add TRY/CATCH to here, but we don't want to spin loop on the same error
m_log . WarnFormat ( LogHeader + ": Listening for new connections on port {0}..." , m_port . ToString ( ) ) ;
TcpClient tcpclient = m_listener . AcceptTcpClient ( ) ;
IPAddress addr = ( ( IPEndPoint ) tcpclient . Client . RemoteEndPoint ) . Address ;
int port = ( ( IPEndPoint ) tcpclient . Client . RemoteEndPoint ) . Port ;
SceneToPhysEngineSyncServer . m_totalConnections + + ;
// m_log.DebugFormat("{0}: m_totalConnections = {1}", LogHeader, SceneToPhysEngineSyncServer.m_totalConnections);
ActorStatus actorStatus = GetActorStatus ( tcpclient ) ;
switch ( actorStatus )
{
case ActorStatus . Sync :
// Add the SceneToPhysEngineConnector to the list
SceneToPhysEngineConnector sceneToPEConnector = new SceneToPhysEngineConnector ( + + peCounter , m_scene , tcpclient , this ) ;
AddSyncedPhysEngine ( sceneToPEConnector ) ;
break ;
case ActorStatus . Idle :
IdlePhysEngineInfo idleSE = new IdlePhysEngineInfo ( tcpclient ) ;
m_log . DebugFormat ( "{0}: adding an idle SE ({1}:{2})" , LogHeader , addr , port ) ;
m_idlePhysEngineList . Add ( idleSE ) ;
break ;
default :
m_log . DebugFormat ( "{0}: Unknown actor status" , LogHeader ) ;
break ;
}
}
}
catch ( SocketException e )
{
m_log . WarnFormat ( "{0}: [Listen] SocketException: {1}" , LogHeader , e ) ;
}
}
/ *
public void RegisterSyncedPhysEngine ( SceneToPhysEngineConnector sceneToSEConnector )
{
//first, remove it from the idle list
m_idlePhysEngineList . Remove ( sceneToSEConnector ) ;
//now, added to the synced SE list
AddSyncedPhysEngine ( sceneToSEConnector ) ;
}
* * /
// Broadcast a message to all connected RegionSyncClients
public void SendToAllConnectedPE ( RegionSyncMessage msg )
{
if ( m_physEngineConnectors . Count > 0 )
{
m_log . Debug ( LogHeader + ": region " + m_scene . RegionInfo . RegionName + " Broadcast to PhysEngine, msg " + msg . Type ) ;
foreach ( SceneToPhysEngineConnector peConnector in m_physEngineConnectors )
{
peConnector . Send ( msg ) ;
}
}
}
//TO FINISH: Find the right SceneToSEConnector to forward the message
public void SendToPE ( RegionSyncMessage . MsgType msgType , SceneObjectGroup sog )
{
SceneToPhysEngineConnector peConnector = GetSceneToPEConnector ( sog ) ;
if ( peConnector ! = null )
{
peConnector . SendObjectUpdate ( msgType , sog ) ;
}
}
//This is to send a message, rsm, to phys engine, and the message is about object SOG. E.g. RemovedObject
public void SendToPE ( RegionSyncMessage rsm , SceneObjectGroup sog )
{
SceneToPhysEngineConnector peConnector = GetSceneToPEConnector ( sog ) ;
if ( peConnector ! = null )
{
peConnector . Send ( rsm ) ;
}
}
private SceneToPhysEngineConnector GetSceneToPEConnector ( SceneObjectGroup sog )
{
if ( m_physEngineConnectors . Count = = 0 )
return null ;
if ( sog = = null )
{
return m_physEngineConnectors [ 0 ] ;
}
else
{
// TODO: connection of physics engine to quarks. Next line commented out
// SceneToPhysEngineConnector peConnector = m_quarksInScene[quarkID].PEConnector;
if ( PEConnector = = null )
{
m_log . Warn ( LogHeader + sog . AbsolutePosition . ToString ( ) + " not covered by any physics engine" ) ;
}
return PEConnector ;
}
}
private ActorStatus GetActorStatus ( TcpClient tcpclient )
{
m_log . Debug ( LogHeader + ": Get Actor status" ) ;
RegionSyncMessage msg = new RegionSyncMessage ( tcpclient . GetStream ( ) ) ;
ActorStatus actorStatus ;
switch ( msg . Type )
{
case RegionSyncMessage . MsgType . ActorStatus :
{
string status = Encoding . ASCII . GetString ( msg . Data , 0 , msg . Length ) ;
m_log . Debug ( LogHeader + ": recv status: " + status ) ;
actorStatus = ( ActorStatus ) Convert . ToInt32 ( status ) ;
break ;
}
default :
{
m_log . Error ( LogHeader + ": Expect Message Type: ActorStatus" ) ;
RegionSyncMessage . HandleError ( "[REGION SYNC SERVER]" , msg , String . Format ( "{0} Expect Message Type: ActorType" , "[REGION SYNC SERVER]" ) ) ;
return ActorStatus . Null ;
}
}
return actorStatus ;
}
#region Event Handlers
#endregion Event Handlers
#region Load balancing members and functions
/ *
//keep track of idle physics engines that are in the process of load balancing (they are off the idle list, but not a working physics engine yet (not sync'ing with Scene yet)).
private Dictionary < string , IdlePhysEngineInfo > m_loadBalancingIdleSEs = new Dictionary < string , IdlePhysEngineInfo > ( ) ;
public void HandleLoadBalanceRequest ( SceneToPhysEngineConnector seConnctor )
{
//Let's start a thread to do the job, so that we can return quickly and don't block on ReceiveLoop()
Thread partitionThread = new Thread ( new ParameterizedThreadStart ( TriggerLoadBalanceProcess ) ) ;
partitionThread . Name = "TriggerLoadBalanceProcess" ;
partitionThread . Start ( ( object ) seConnctor ) ;
}
public void TriggerLoadBalanceProcess ( object arg )
{
SceneToPhysEngineConnector seConnctor = ( SceneToPhysEngineConnector ) arg ;
IdlePhysEngineInfo idlePhysEngineInfo = GetIdlePhysEngineConnector ( ) ;
if ( idlePhysEngineInfo ! = null )
{
RegionSyncMessage msg = new RegionSyncMessage ( RegionSyncMessage . MsgType . LoadMigrationNotice ) ;
Send ( idlePhysEngineInfo . TClient , msg . ToBytes ( ) ) ;
m_log . Debug ( LogHeader + ": HandleLoadBalanceRequest from " + seConnctor . Description + ", picked idle SE: " + idlePhysEngineInfo . ID ) ;
//keep track of which overload physics engine is paired up with which idle physics engine
idlePhysEngineInfo . AwaitOverloadedSE = seConnctor ;
m_loadBalancingIdleSEs . Add ( idlePhysEngineInfo . ID , idlePhysEngineInfo ) ;
m_log . Debug ( "ToSEConnector portal: local -" +
( ( IPEndPoint ) idlePhysEngineInfo . TClient . Client . LocalEndPoint ) . Address . ToString ( ) + ":" + ( ( IPEndPoint ) idlePhysEngineInfo . TClient . Client . LocalEndPoint ) . Port
+ "; remote - " + ( ( IPEndPoint ) idlePhysEngineInfo . TClient . Client . RemoteEndPoint ) . Address . ToString ( ) + ":"
+ ( ( IPEndPoint ) idlePhysEngineInfo . TClient . Client . RemoteEndPoint ) . Port ) ;
//Now we expect the idle physics engine to reply back
msg = new RegionSyncMessage ( idlePhysEngineInfo . TClient . GetStream ( ) ) ;
if ( msg . Type ! = RegionSyncMessage . MsgType . LoadMigrationListenerInitiated )
{
m_log . Warn ( LogHeader + ": should receive a message of type LoadMigrationListenerInitiated, but received " + msg . Type . ToString ( ) ) ;
}
else
{
//Before the load is migrated from overloaded physics engine to the idle engine, sync with the DB to update the state in DB
List < EntityBase > entities = m_scene . GetEntities ( ) ;
foreach ( EntityBase entity in entities )
{
if ( ! entity . IsDeleted & & entity is SceneObjectGroup & & ( ( SceneObjectGroup ) entity ) . HasGroupChanged )
{
m_scene . ForceSceneObjectBackup ( ( SceneObjectGroup ) entity ) ;
}
}
OSDMap data = DeserializeMessage ( msg ) ;
if ( ! data . ContainsKey ( "ip" ) | | ! data . ContainsKey ( "port" ) )
{
m_log . Warn ( LogHeader + ": parameters missing in SceneLocation message from Scene, need to have ip, port" ) ;
return ;
}
//echo the information back to the overloaded physics engine
seConnctor . Send ( new RegionSyncMessage ( RegionSyncMessage . MsgType . LoadBalanceResponse , OSDParser . SerializeJsonString ( data ) ) ) ;
m_log . Debug ( LogHeader + " now remove physics engine " + idlePhysEngineInfo . ID + " from idle SE list, and create SceneToPhysEngineConnector to it" ) ;
//create a SceneToSEConnector for the idle physics engine, who will be sync'ing with this SyncServer soon
SceneToPhysEngineConnector sceneToSEConnector = new SceneToPhysEngineConnector ( + + peCounter , m_scene , idlePhysEngineInfo . TClient , this ) ;
//Now remove the physics engine from the idle SE list
m_idlePhysEngineList . Remove ( idlePhysEngineInfo ) ;
//AddSyncedPhysEngine(sceneToSEConnector);
}
}
else
{
seConnctor . SendLoadBalanceRejection ( "no idle physics engines" ) ;
}
}
* /
HashSet < string > exceptions = new HashSet < string > ( ) ;
private OSDMap DeserializeMessage ( RegionSyncMessage msg )
{
OSDMap data = null ;
try
{
data = OSDParser . DeserializeJson ( Encoding . ASCII . GetString ( msg . Data , 0 , msg . Length ) ) as OSDMap ;
}
catch ( Exception e )
{
lock ( exceptions )
// If this is a new message, then print the underlying data that caused it
if ( ! exceptions . Contains ( e . Message ) )
m_log . Error ( LogHeader + " " + Encoding . ASCII . GetString ( msg . Data , 0 , msg . Length ) ) ;
data = null ;
}
return data ;
}
private void Send ( TcpClient tcpclient , byte [ ] data )
{
if ( tcpclient . Connected )
{
try
{
tcpclient . GetStream ( ) . BeginWrite ( data , 0 , data . Length , ar = >
{
if ( tcpclient . Connected )
{
try
{
tcpclient . GetStream ( ) . EndWrite ( ar ) ;
}
catch ( Exception )
{ }
}
} , null ) ;
}
catch ( IOException )
{
m_log . WarnFormat ( "{0} physics Engine has disconnected." , LogHeader ) ;
}
}
}
private IdlePhysEngineInfo GetIdlePhysEngineConnector ( )
{
if ( m_idlePhysEngineList . Count = = 0 )
return null ;
IdlePhysEngineInfo idleSEInfo = m_idlePhysEngineList [ 0 ] ;
m_idlePhysEngineList . Remove ( idleSEInfo ) ;
return idleSEInfo ;
}
#endregion Load balancing functions
#region Message Logging
public static bool logInput = false ;
public static bool logOutput = true ;
2011-03-11 23:56:33 +00:00
public static bool logEnabled = false ;
2011-02-26 00:30:52 +00:00
private class PhysMsgLogger
{
public DateTime startTime ;
public string path = null ;
public System . IO . TextWriter Log = null ;
}
private static PhysMsgLogger logWriter = null ;
private static TimeSpan logMaxFileTime = new TimeSpan ( 0 , 5 , 0 ) ; // (h,m,s) => 5 minutes
public static string logDir = "/stats/stats" ;
private static object logLocker = new Object ( ) ;
public static void PhysLogMessage ( bool direction , RegionSyncMessage rsm )
{
if ( ! logEnabled ) return ; // save to work of the ToStringFull if not enabled
PhysLogMessage ( direction , rsm . ToStringFull ( ) ) ;
}
/// <summary>
/// Log a physics bucket message
/// </summary>
/// <param name="direction">True of message originated from the agent</param>
/// <param name="msg">the message to log</param>
public static void PhysLogMessage ( bool direction , string msg )
{
if ( ! logEnabled ) return ;
lock ( logLocker )
{
try
{
DateTime now = DateTime . Now ;
if ( logWriter = = null | | ( now > logWriter . startTime + logMaxFileTime ) )
{
if ( logWriter ! = null & & logWriter . Log ! = null )
{
logWriter . Log . Close ( ) ;
logWriter . Log . Dispose ( ) ;
logWriter . Log = null ;
}
// First log file or time has expired, start writing to a new log file
logWriter = new PhysMsgLogger ( ) ;
logWriter . startTime = now ;
logWriter . path = ( logDir . Length > 0 ? logDir + System . IO . Path . DirectorySeparatorChar . ToString ( ) : "" )
+ String . Format ( "physics-{0}.log" , now . ToString ( "yyyyMMddHHmmss" ) ) ;
logWriter . Log = new StreamWriter ( File . Open ( logWriter . path , FileMode . Append , FileAccess . Write ) ) ;
}
if ( logWriter ! = null & & logWriter . Log ! = null )
{
StringBuilder buff = new StringBuilder ( ) ;
buff . Append ( now . ToString ( "yyyyMMddHHmmssfff" ) ) ;
buff . Append ( " " ) ;
buff . Append ( direction ? "A->S:" : "S->A:" ) ;
buff . Append ( msg ) ;
buff . Append ( "\r\n" ) ;
logWriter . Log . Write ( buff . ToString ( ) ) ;
}
}
catch ( Exception e )
{
// m_log.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
logEnabled = false ;
}
}
return ;
}
public static void PhysLogMessageClose ( )
{
if ( logWriter ! = null & & logWriter . Log ! = null )
{
logWriter . Log . Close ( ) ;
logWriter . Log . Dispose ( ) ;
logWriter . Log = null ;
logWriter = null ;
}
logEnabled = false ;
}
#endregion Message Logging
}
}