mirror of
https://github.com/opensim/opensim.git
synced 2026-08-05 00:46:02 +08:00
bad merge?
This commit is contained in:
@@ -27,11 +27,14 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Mono.Addins;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
@@ -57,12 +60,51 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
private IAssetService m_AssetService;
|
||||
private bool m_Enabled = true;
|
||||
private string m_URL;
|
||||
<<<<<<< HEAD
|
||||
private string m_URL2;
|
||||
private string m_RedirectURL = null;
|
||||
private string m_RedirectURL2 = null;
|
||||
=======
|
||||
|
||||
struct aPollRequest
|
||||
{
|
||||
public PollServiceMeshEventArgs thepoll;
|
||||
public UUID reqID;
|
||||
public Hashtable request;
|
||||
}
|
||||
|
||||
public class aPollResponse
|
||||
{
|
||||
public Hashtable response;
|
||||
public int bytes;
|
||||
public int lod;
|
||||
}
|
||||
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private static GetMeshHandler m_getMeshHandler;
|
||||
|
||||
private IAssetService m_assetService = null;
|
||||
|
||||
private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
|
||||
private static Thread[] m_workerThreads = null;
|
||||
|
||||
private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
|
||||
new OpenMetaverse.BlockingQueue<aPollRequest>();
|
||||
|
||||
private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
|
||||
>>>>>>> avn/ubitvar
|
||||
|
||||
#region Region Module interfaceBase Members
|
||||
|
||||
~GetMeshModule()
|
||||
{
|
||||
foreach (Thread t in m_workerThreads)
|
||||
Watchdog.AbortThread(t.ManagedThreadId);
|
||||
|
||||
}
|
||||
|
||||
public Type ReplaceableInterface
|
||||
{
|
||||
get { return null; }
|
||||
@@ -87,8 +129,12 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
if (m_URL2 != string.Empty)
|
||||
{
|
||||
m_Enabled = true;
|
||||
<<<<<<< HEAD
|
||||
m_RedirectURL2 = config.GetString("GetMesh2RedirectURL");
|
||||
}
|
||||
=======
|
||||
|
||||
>>>>>>> avn/ubitvar
|
||||
}
|
||||
|
||||
public void AddRegion(Scene pScene)
|
||||
@@ -97,6 +143,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
return;
|
||||
|
||||
m_scene = pScene;
|
||||
|
||||
m_assetService = pScene.AssetService;
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene scene)
|
||||
@@ -105,6 +153,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
return;
|
||||
|
||||
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
|
||||
m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
|
||||
m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
|
||||
|
||||
m_scene = null;
|
||||
}
|
||||
|
||||
@@ -115,6 +166,27 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
|
||||
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
||||
// We'll reuse the same handler for all requests.
|
||||
m_getMeshHandler = new GetMeshHandler(m_assetService);
|
||||
m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
|
||||
m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
|
||||
|
||||
if (m_workerThreads == null)
|
||||
{
|
||||
m_workerThreads = new Thread[2];
|
||||
|
||||
for (uint i = 0; i < 2; i++)
|
||||
{
|
||||
m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
|
||||
String.Format("MeshWorkerThread{0}", i),
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
false,
|
||||
null,
|
||||
int.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -124,9 +196,147 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
#endregion
|
||||
|
||||
private void DoMeshRequests()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
aPollRequest poolreq = m_queue.Dequeue();
|
||||
|
||||
poolreq.thepoll.Process(poolreq);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent.
|
||||
public void ThrottleUpdate(ScenePresence p)
|
||||
{
|
||||
UUID user = p.UUID;
|
||||
int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Asset);
|
||||
PollServiceMeshEventArgs args;
|
||||
if (m_pollservices.TryGetValue(user, out args))
|
||||
{
|
||||
args.UpdateThrottle(imagethrottle, p);
|
||||
}
|
||||
}
|
||||
|
||||
private class PollServiceMeshEventArgs : PollServiceEventArgs
|
||||
{
|
||||
private List<Hashtable> requests =
|
||||
new List<Hashtable>();
|
||||
private Dictionary<UUID, aPollResponse> responses =
|
||||
new Dictionary<UUID, aPollResponse>();
|
||||
|
||||
private Scene m_scene;
|
||||
private MeshCapsDataThrottler m_throttler;
|
||||
public PollServiceMeshEventArgs(string uri, UUID pId, Scene scene) :
|
||||
base(null, uri, null, null, null, pId, int.MaxValue)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene, pId);
|
||||
// x is request id, y is userid
|
||||
HasEvents = (x, y) =>
|
||||
{
|
||||
lock (responses)
|
||||
{
|
||||
bool ret = m_throttler.hasEvents(x, responses);
|
||||
m_throttler.ProcessTime();
|
||||
return ret;
|
||||
|
||||
}
|
||||
};
|
||||
GetEvents = (x, y) =>
|
||||
{
|
||||
lock (responses)
|
||||
{
|
||||
try
|
||||
{
|
||||
return responses[x].response;
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_throttler.ProcessTime();
|
||||
responses.Remove(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
// x is request id, y is request data hashtable
|
||||
Request = (x, y) =>
|
||||
{
|
||||
aPollRequest reqinfo = new aPollRequest();
|
||||
reqinfo.thepoll = this;
|
||||
reqinfo.reqID = x;
|
||||
reqinfo.request = y;
|
||||
|
||||
m_queue.Enqueue(reqinfo);
|
||||
};
|
||||
|
||||
// this should never happen except possible on shutdown
|
||||
NoEvents = (x, y) =>
|
||||
{
|
||||
/*
|
||||
lock (requests)
|
||||
{
|
||||
Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
|
||||
requests.Remove(request);
|
||||
}
|
||||
*/
|
||||
Hashtable response = new Hashtable();
|
||||
|
||||
response["int_response_code"] = 500;
|
||||
response["str_response_string"] = "Script timeout";
|
||||
response["content_type"] = "text/plain";
|
||||
response["keepalive"] = false;
|
||||
response["reusecontext"] = false;
|
||||
|
||||
return response;
|
||||
};
|
||||
}
|
||||
|
||||
public void Process(aPollRequest requestinfo)
|
||||
{
|
||||
Hashtable response;
|
||||
|
||||
UUID requestID = requestinfo.reqID;
|
||||
|
||||
// If the avatar is gone, don't bother to get the texture
|
||||
if (m_scene.GetScenePresence(Id) == null)
|
||||
{
|
||||
response = new Hashtable();
|
||||
|
||||
response["int_response_code"] = 500;
|
||||
response["str_response_string"] = "Script timeout";
|
||||
response["content_type"] = "text/plain";
|
||||
response["keepalive"] = false;
|
||||
response["reusecontext"] = false;
|
||||
|
||||
lock (responses)
|
||||
responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
response = m_getMeshHandler.Handle(requestinfo.request);
|
||||
lock (responses)
|
||||
{
|
||||
responses[requestID] = new aPollResponse()
|
||||
{
|
||||
bytes = (int)response["int_bytes"],
|
||||
lod = (int)response["int_lod"],
|
||||
response = response
|
||||
};
|
||||
|
||||
}
|
||||
m_throttler.ProcessTime();
|
||||
}
|
||||
|
||||
internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
|
||||
{
|
||||
m_throttler.UpdateThrottle(pimagethrottle, p);
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
UUID capID = UUID.Random();
|
||||
bool getMeshRegistered = false;
|
||||
|
||||
@@ -140,6 +350,35 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
caps.RegisterHandler(
|
||||
"GetMesh",
|
||||
new GetMeshHandler("/CAPS/" + capID + "/", m_AssetService, "GetMesh", agentID.ToString(), m_RedirectURL));
|
||||
=======
|
||||
// UUID capID = UUID.Random();
|
||||
if (m_URL == "localhost")
|
||||
{
|
||||
string capUrl = "/CAPS/" + UUID.Random() + "/";
|
||||
|
||||
// Register this as a poll service
|
||||
PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(capUrl, agentID, m_scene);
|
||||
|
||||
args.Type = PollServiceEventArgs.EventType.Mesh;
|
||||
MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
|
||||
|
||||
string hostName = m_scene.RegionInfo.ExternalHostName;
|
||||
uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
|
||||
string protocol = "http";
|
||||
|
||||
if (MainServer.Instance.UseSSL)
|
||||
{
|
||||
hostName = MainServer.Instance.SSLCommonName;
|
||||
port = MainServer.Instance.SSLPort;
|
||||
protocol = "https";
|
||||
}
|
||||
caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
|
||||
m_pollservices[agentID] = args;
|
||||
m_capsDict[agentID] = capUrl;
|
||||
|
||||
|
||||
|
||||
>>>>>>> avn/ubitvar
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -164,6 +403,177 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
caps.RegisterHandler("GetMesh2", m_URL2);
|
||||
}
|
||||
}
|
||||
private void DeregisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
string capUrl;
|
||||
PollServiceMeshEventArgs args;
|
||||
if (m_capsDict.TryGetValue(agentID, out capUrl))
|
||||
{
|
||||
MainServer.Instance.RemoveHTTPHandler("", capUrl);
|
||||
m_capsDict.Remove(agentID);
|
||||
}
|
||||
if (m_pollservices.TryGetValue(agentID, out args))
|
||||
{
|
||||
m_pollservices.Remove(agentID);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class MeshCapsDataThrottler
|
||||
{
|
||||
|
||||
private volatile int currenttime = 0;
|
||||
private volatile int lastTimeElapsed = 0;
|
||||
private volatile int BytesSent = 0;
|
||||
private int Lod3 = 0;
|
||||
private int Lod2 = 0;
|
||||
private int Lod1 = 0;
|
||||
private int UserSetThrottle = 0;
|
||||
private int UDPSetThrottle = 0;
|
||||
private int CapSetThrottle = 0;
|
||||
private float CapThrottleDistributon = 0.30f;
|
||||
private readonly Scene m_scene;
|
||||
private ThrottleOutPacketType Throttle;
|
||||
private readonly UUID User;
|
||||
|
||||
public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene, UUID puser)
|
||||
{
|
||||
ThrottleBytes = pBytes;
|
||||
lastTimeElapsed = Util.EnvironmentTickCount();
|
||||
Throttle = ThrottleOutPacketType.Asset;
|
||||
m_scene = pScene;
|
||||
User = puser;
|
||||
}
|
||||
|
||||
|
||||
public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
|
||||
{
|
||||
const float ThirtyPercent = 0.30f;
|
||||
const float FivePercent = 0.05f;
|
||||
PassTime();
|
||||
// Note, this is called IN LOCK
|
||||
bool haskey = responses.ContainsKey(key);
|
||||
|
||||
if (responses.Count > 2)
|
||||
{
|
||||
SplitThrottle(ThirtyPercent);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitThrottle(FivePercent);
|
||||
}
|
||||
|
||||
if (!haskey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
aPollResponse response;
|
||||
if (responses.TryGetValue(key, out response))
|
||||
{
|
||||
float LOD3Over = (((ThrottleBytes*CapThrottleDistributon)%50000) + 1);
|
||||
float LOD2Over = (((ThrottleBytes*CapThrottleDistributon)%10000) + 1);
|
||||
// Normal
|
||||
if (BytesSent + response.bytes <= ThrottleBytes)
|
||||
{
|
||||
BytesSent += response.bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
// Lod3 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
|
||||
else if (response.bytes > ThrottleBytes && Lod3 <= ((LOD3Over < 1)? 1: LOD3Over) )
|
||||
{
|
||||
Interlocked.Increment(ref Lod3);
|
||||
BytesSent += response.bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
// Lod2 Over Throttle protection to keep things processing even when the throttle bandwidth is set too little.
|
||||
else if (response.bytes > ThrottleBytes && Lod2 <= ((LOD2Over < 1) ? 1 : LOD2Over))
|
||||
{
|
||||
Interlocked.Increment(ref Lod2);
|
||||
BytesSent += response.bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return haskey;
|
||||
}
|
||||
public void SubtractBytes(int bytes,int lod)
|
||||
{
|
||||
BytesSent -= bytes;
|
||||
}
|
||||
private void SplitThrottle(float percentMultiplier)
|
||||
{
|
||||
|
||||
if (CapThrottleDistributon != percentMultiplier) // don't switch it if it's already set at the % multipler
|
||||
{
|
||||
CapThrottleDistributon = percentMultiplier;
|
||||
ScenePresence p;
|
||||
if (m_scene.TryGetScenePresence(User, out p)) // If we don't get a user they're not here anymore.
|
||||
{
|
||||
// AlterThrottle(UserSetThrottle, p);
|
||||
UpdateThrottle(UserSetThrottle, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessTime()
|
||||
{
|
||||
PassTime();
|
||||
}
|
||||
|
||||
|
||||
private void PassTime()
|
||||
{
|
||||
currenttime = Util.EnvironmentTickCount();
|
||||
int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
|
||||
//processTimeBasedActions(responses);
|
||||
if (currenttime - timeElapsed >= 1000)
|
||||
{
|
||||
lastTimeElapsed = Util.EnvironmentTickCount();
|
||||
BytesSent -= ThrottleBytes;
|
||||
if (BytesSent < 0) BytesSent = 0;
|
||||
if (BytesSent < ThrottleBytes)
|
||||
{
|
||||
Lod3 = 0;
|
||||
Lod2 = 0;
|
||||
Lod1 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void AlterThrottle(int setting, ScenePresence p)
|
||||
{
|
||||
p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
|
||||
}
|
||||
|
||||
public int ThrottleBytes
|
||||
{
|
||||
get { return CapSetThrottle; }
|
||||
set { CapSetThrottle = value; }
|
||||
}
|
||||
|
||||
internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
|
||||
{
|
||||
// Client set throttle !
|
||||
UserSetThrottle = pimagethrottle;
|
||||
CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
|
||||
// UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
|
||||
|
||||
float udp = 1.0f - CapThrottleDistributon;
|
||||
if(udp < 0.7f)
|
||||
udp = 0.7f;
|
||||
UDPSetThrottle = (int) ((float)pimagethrottle * udp);
|
||||
if (CapSetThrottle < 4068)
|
||||
CapSetThrottle = 4068; // at least two discovery mesh
|
||||
p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
|
||||
ProcessTime();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user