Added load/unload queue size limit
Added option to share script load/unload thread between regions Added event execution queue size limit + some bugfixes from all the changesThreadPoolClientBranch
parent
8ccc12d642
commit
e06ee9fd4b
|
@ -99,6 +99,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int numberOfThreads;
|
internal int numberOfThreads;
|
||||||
|
|
||||||
|
internal static int EventExecutionMaxQueueSize;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum time one function can use for execution before we perform a thread kill.
|
/// Maximum time one function can use for execution before we perform a thread kill.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -208,6 +210,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000);
|
maxFunctionExecutionTimems = m_ScriptEngine.ScriptConfigSource.GetInt("MaxEventExecutionTimeMs", 5000);
|
||||||
EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false);
|
EnforceMaxExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("EnforceMaxEventExecutionTime", false);
|
||||||
KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false);
|
KillScriptOnMaxFunctionExecutionTime = m_ScriptEngine.ScriptConfigSource.GetBoolean("DeactivateScriptOnTimeout", false);
|
||||||
|
EventExecutionMaxQueueSize = m_ScriptEngine.ScriptConfigSource.GetInt("EventExecutionMaxQueueSize", 300);
|
||||||
|
|
||||||
// Now refresh config in all threads
|
// Now refresh config in all threads
|
||||||
lock (eventQueueThreadsLock)
|
lock (eventQueueThreadsLock)
|
||||||
|
@ -362,6 +365,13 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
lock (queueLock)
|
lock (queueLock)
|
||||||
{
|
{
|
||||||
|
if (eventQueue.Count >= EventExecutionMaxQueueSize)
|
||||||
|
{
|
||||||
|
m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName, "ERROR: Event execution queue item count is at " + eventQueue.Count + ". Config variable \"EventExecutionMaxQueueSize\" is set to " + EventExecutionMaxQueueSize + ", so ignoring new event.");
|
||||||
|
m_ScriptEngine.Log.Error(m_ScriptEngine.ScriptEngineName, "Event ignored: localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a structure and add data
|
// Create a structure and add data
|
||||||
QueueItemStruct QIS = new QueueItemStruct();
|
QueueItemStruct QIS = new QueueItemStruct();
|
||||||
QIS.localID = localID;
|
QIS.localID = localID;
|
||||||
|
|
|
@ -38,19 +38,20 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maintenance thread. Enforcing max execution time for example.
|
/// Maintenance thread. Enforcing max execution time for example.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Thread MaintenanceThreadThread;
|
public Thread MaintenanceThreadThread;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts maintenance thread
|
/// Starts maintenance thread
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void StartMaintenanceThread()
|
private void StartMaintenanceThread()
|
||||||
{
|
{
|
||||||
StopMaintenanceThread();
|
if (MaintenanceThreadThread == null)
|
||||||
|
{
|
||||||
MaintenanceThreadThread = new Thread(MaintenanceLoop);
|
MaintenanceThreadThread = new Thread(MaintenanceLoop);
|
||||||
MaintenanceThreadThread.Name = "ScriptMaintenanceThread";
|
MaintenanceThreadThread.Name = "ScriptMaintenanceThread";
|
||||||
MaintenanceThreadThread.IsBackground = true;
|
MaintenanceThreadThread.IsBackground = true;
|
||||||
MaintenanceThreadThread.Start();
|
MaintenanceThreadThread.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -92,23 +92,26 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
m_log = logger;
|
m_log = logger;
|
||||||
ConfigSource = config;
|
ConfigSource = config;
|
||||||
Log.Verbose(ScriptEngineName, "ScriptEngine initializing");
|
Log.Verbose(ScriptEngineName, "ScriptEngine initializing");
|
||||||
Log.Verbose(ScriptEngineName, "Reading configuration from config section \"" + ScriptEngineName + "\"");
|
|
||||||
|
|
||||||
// Make sure we have config
|
// Make sure we have config
|
||||||
if (ConfigSource.Configs[ScriptEngineName] == null)
|
if (ConfigSource.Configs[ScriptEngineName] == null)
|
||||||
ConfigSource.AddConfig(ScriptEngineName);
|
ConfigSource.AddConfig(ScriptEngineName);
|
||||||
ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
|
ScriptConfigSource = ConfigSource.Configs[ScriptEngineName];
|
||||||
|
|
||||||
|
|
||||||
//m_logger.Status(ScriptEngineName, "InitializeEngine");
|
//m_logger.Status(ScriptEngineName, "InitializeEngine");
|
||||||
|
|
||||||
// Create all objects we'll be using
|
// Create all objects we'll be using
|
||||||
m_EventQueueManager = new EventQueueManager(this);
|
m_EventQueueManager = new EventQueueManager(this);
|
||||||
m_EventManager = new EventManager(this, HookUpToServer);
|
m_EventManager = new EventManager(this, HookUpToServer);
|
||||||
|
// We need to start it
|
||||||
|
newScriptManager.Start();
|
||||||
m_ScriptManager = newScriptManager;
|
m_ScriptManager = newScriptManager;
|
||||||
m_AppDomainManager = new AppDomainManager(this);
|
m_AppDomainManager = new AppDomainManager(this);
|
||||||
m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this);
|
m_ASYNCLSLCommandManager = new AsyncLSLCommandManager(this);
|
||||||
m_MaintenanceThread = new MaintenanceThread(this);
|
m_MaintenanceThread = new MaintenanceThread(this);
|
||||||
|
|
||||||
|
Log.Verbose(ScriptEngineName, "Reading configuration from config section \"" + ScriptEngineName + "\"");
|
||||||
ReadConfig();
|
ReadConfig();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,9 +62,11 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
#region Declares
|
#region Declares
|
||||||
|
|
||||||
private Thread scriptLoadUnloadThread;
|
private Thread scriptLoadUnloadThread;
|
||||||
|
private static Thread staticScriptLoadUnloadThread;
|
||||||
private int scriptLoadUnloadThread_IdleSleepms;
|
private int scriptLoadUnloadThread_IdleSleepms;
|
||||||
private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
|
private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
|
||||||
|
private static bool PrivateThread;
|
||||||
|
private int LoadUnloadMaxQueueSize;
|
||||||
|
|
||||||
// Load/Unload structure
|
// Load/Unload structure
|
||||||
private struct LUStruct
|
private struct LUStruct
|
||||||
|
@ -98,6 +100,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
public void ReadConfig()
|
public void ReadConfig()
|
||||||
{
|
{
|
||||||
scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
|
scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
|
||||||
|
PrivateThread = m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false);
|
||||||
|
LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Object init/shutdown
|
#region Object init/shutdown
|
||||||
|
@ -107,14 +111,52 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
|
public ScriptManager(ScriptEngineBase.ScriptEngine scriptEngine)
|
||||||
{
|
{
|
||||||
m_scriptEngine = scriptEngine;
|
m_scriptEngine = scriptEngine;
|
||||||
// We should not read config during startup as ScriptEngine may not have config object yet
|
}
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
ReadConfig();
|
||||||
|
|
||||||
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
|
||||||
scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
|
|
||||||
scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
|
//
|
||||||
scriptLoadUnloadThread.IsBackground = true;
|
// CREATE THREAD
|
||||||
scriptLoadUnloadThread.Priority = ThreadPriority.BelowNormal;
|
// Private or shared
|
||||||
scriptLoadUnloadThread.Start();
|
//
|
||||||
|
if (PrivateThread)
|
||||||
|
{
|
||||||
|
// Assign one thread per region
|
||||||
|
scriptLoadUnloadThread = StartScriptLoadUnloadThread();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Shared thread - make sure one exist, then assign it to the private
|
||||||
|
if (staticScriptLoadUnloadThread == null)
|
||||||
|
{
|
||||||
|
staticScriptLoadUnloadThread = StartScriptLoadUnloadThread();
|
||||||
|
}
|
||||||
|
scriptLoadUnloadThread = staticScriptLoadUnloadThread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int privateThreadCount = 0;
|
||||||
|
private Thread StartScriptLoadUnloadThread()
|
||||||
|
{
|
||||||
|
Thread t = new Thread(ScriptLoadUnloadThreadLoop);
|
||||||
|
string name = "ScriptLoadUnloadThread:";
|
||||||
|
if (PrivateThread)
|
||||||
|
{
|
||||||
|
name += "Private:" + privateThreadCount;
|
||||||
|
privateThreadCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name += "Shared";
|
||||||
|
}
|
||||||
|
t.Name = name;
|
||||||
|
t.IsBackground = true;
|
||||||
|
t.Priority = ThreadPriority.Normal;
|
||||||
|
t.Start();
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScriptManager()
|
~ScriptManager()
|
||||||
|
@ -122,6 +164,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
// Abort load/unload thread
|
// Abort load/unload thread
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
PleaseShutdown = true;
|
||||||
|
Thread.Sleep(100);
|
||||||
if (scriptLoadUnloadThread != null)
|
if (scriptLoadUnloadThread != null)
|
||||||
{
|
{
|
||||||
if (scriptLoadUnloadThread.IsAlive == true)
|
if (scriptLoadUnloadThread.IsAlive == true)
|
||||||
|
@ -148,6 +192,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
{
|
{
|
||||||
if (LUQueue.Count == 0)
|
if (LUQueue.Count == 0)
|
||||||
Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
|
Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
|
||||||
|
if (PleaseShutdown)
|
||||||
|
return;
|
||||||
if (LUQueue.Count > 0)
|
if (LUQueue.Count > 0)
|
||||||
{
|
{
|
||||||
LUStruct item = LUQueue.Dequeue();
|
LUStruct item = LUQueue.Dequeue();
|
||||||
|
@ -185,7 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region Start/Stop/Reset script
|
#region Start/Stop/Reset script
|
||||||
|
|
||||||
|
@ -198,6 +244,12 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
/// <param name="localID"></param>
|
/// <param name="localID"></param>
|
||||||
public void StartScript(uint localID, LLUUID itemID, string Script)
|
public void StartScript(uint localID, LLUUID itemID, string Script)
|
||||||
{
|
{
|
||||||
|
if (LUQueue.Count >= LoadUnloadMaxQueueSize)
|
||||||
|
{
|
||||||
|
m_scriptEngine.Log.Error(m_scriptEngine.ScriptEngineName, "ERROR: Load/unload queue item count is at " + LUQueue.Count + ". Config variable \"LoadUnloadMaxQueueSize\" is set to " + LoadUnloadMaxQueueSize + ", so ignoring new script.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LUStruct ls = new LUStruct();
|
LUStruct ls = new LUStruct();
|
||||||
ls.localID = localID;
|
ls.localID = localID;
|
||||||
ls.itemID = itemID;
|
ls.itemID = itemID;
|
||||||
|
@ -224,9 +276,8 @@ namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
|
||||||
//private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
|
//private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
|
||||||
|
|
||||||
public abstract void _StartScript(uint localID, LLUUID itemID, string Script);
|
public abstract void _StartScript(uint localID, LLUUID itemID, string Script);
|
||||||
|
|
||||||
public abstract void _StopScript(uint localID, LLUUID itemID);
|
public abstract void _StopScript(uint localID, LLUUID itemID);
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
|
|
||||||
CompiledScript.Source = Script;
|
CompiledScript.Source = Script;
|
||||||
// Add it to our script memstruct
|
// Add it to our script memstruct
|
||||||
SetScript(localID, itemID, CompiledScript);
|
m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, CompiledScript);
|
||||||
|
|
||||||
// We need to give (untrusted) assembly a private instance of BuiltIns
|
// We need to give (untrusted) assembly a private instance of BuiltIns
|
||||||
// this private copy will contain Read-Only FullitemID so that it can bring that on to the server whenever needed.
|
// this private copy will contain Read-Only FullitemID so that it can bring that on to the server whenever needed.
|
||||||
|
@ -144,9 +144,9 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
|
||||||
// Get AppDomain
|
// Get AppDomain
|
||||||
AppDomain ad = LSLBC.Exec.GetAppDomain();
|
AppDomain ad = LSLBC.Exec.GetAppDomain();
|
||||||
// Tell script not to accept new requests
|
// Tell script not to accept new requests
|
||||||
GetScript(localID, itemID).Exec.StopScript();
|
m_scriptEngine.m_ScriptManager.GetScript(localID, itemID).Exec.StopScript();
|
||||||
// Remove from internal structure
|
// Remove from internal structure
|
||||||
RemoveScript(localID, itemID);
|
m_scriptEngine.m_ScriptManager.RemoveScript(localID, itemID);
|
||||||
// Tell AppDomain that we have stopped script
|
// Tell AppDomain that we have stopped script
|
||||||
m_scriptEngine.m_AppDomainManager.StopScript(ad);
|
m_scriptEngine.m_AppDomainManager.StopScript(ad);
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,6 +195,18 @@ ScriptsPerAppDomain=1
|
||||||
; But once active it will process all in queue before sleeping again
|
; But once active it will process all in queue before sleeping again
|
||||||
ScriptLoadUnloadLoopms=30
|
ScriptLoadUnloadLoopms=30
|
||||||
|
|
||||||
|
; Loading and unloading of scripts is queued and processed by a separate thread.
|
||||||
|
; This thread can either be shared among all regions, or private (one thread per region)
|
||||||
|
PrivateScriptLoadUnloadThread=false
|
||||||
|
|
||||||
|
; Maximum number of items in load/unload queue before we start rejecting loads
|
||||||
|
; Note that we will only be rejecting load. Unloads will still be able to queue.
|
||||||
|
LoadUnloadMaxQueueSize=100
|
||||||
|
|
||||||
|
; Maximum number of (LSL) events that can be queued before new events are ignored.
|
||||||
|
EventExecutionMaxQueueSize=300
|
||||||
|
|
||||||
|
|
||||||
; Async LL command sleep
|
; Async LL command sleep
|
||||||
; If no async LL commands are waiting, how long should thread sleep before checking again
|
; If no async LL commands are waiting, how long should thread sleep before checking again
|
||||||
; Async LL commands are LSL-commands that causes an event to be fired back with result
|
; Async LL commands are LSL-commands that causes an event to be fired back with result
|
||||||
|
|
Loading…
Reference in New Issue