From 018645f9f843d1e807a69a63b7dd82c294885eff Mon Sep 17 00:00:00 2001
From: Sean McNamara
Date: Mon, 28 Feb 2011 11:45:50 -0500
Subject: First pass at busy heuristics. Compile-tested only.

---
 .../World/AutoBackup/AutoBackupModule.cs           | 69 ++++++++++++++++++++--
 1 file changed, 63 insertions(+), 6 deletions(-)

(limited to 'OpenSim')

diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
index 54b9b09..98127b7 100644
--- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
+++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
@@ -35,7 +35,9 @@ using log4net;
 using Nini;
 using Nini.Config;
 using OpenSim.Framework;
+using OpenSim.Framework.Statistics;
 using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
 
 
 /*
@@ -319,6 +321,12 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
 
 		void HandleElapsed (object sender, ElapsedEventArgs e)
 		{
+			//TODO?: heuristic thresholds are per-region, so we should probably run heuristics once per region
+			//XXX: Running heuristics once per region could add undue performance penalty for something that's supposed to
+			//check whether the region is too busy! Especially on sims with LOTS of regions.
+			//Alternative: make heuristics thresholds global to the module rather than per-region. Less flexible,
+			// but would allow us to be semantically correct while being easier on perf.
+			//Alternative 2: Run heuristics once per unique set of heuristics threshold parameters! Ay yi yi...
 			if (m_closed)
 				return;
 			bool heuristicsRun = false;
@@ -333,15 +341,18 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
 				//Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region.
 				if ((heuristics && heuristicsRun && heuristicsPassed) || !heuristics) {
 					doRegionBackup (scene);
-				//Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off!
+					//Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off!
 				} else if (heuristics && heuristicsRun && !heuristicsPassed) {
+					m_log.Info ("[AUTO BACKUP MODULE]: Heuristics: too busy to backup " + scene.RegionInfo.RegionName + " right now.");
 					continue;
-				//Logical Deduction: heuristics are on but haven't been run
+					//Logical Deduction: heuristics are on but haven't been run
 				} else {
-					heuristicsPassed = RunHeuristics ();
+					heuristicsPassed = RunHeuristics (scene);
 					heuristicsRun = true;
-					if (!heuristicsPassed)
+					if (!heuristicsPassed) {
+						m_log.Info ("[AUTO BACKUP MODULE]: Heuristics: too busy to backup " + scene.RegionInfo.RegionName + " right now.");
 						continue;
+					}
 					doRegionBackup (scene);
 				}
 			}
@@ -349,6 +360,12 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
 
 		void doRegionBackup (IScene scene)
 		{
+			if (scene.RegionStatus != RegionStatus.Up) {
+				//We won't backup a region that isn't operating normally.
+				m_log.Warn ("[AUTO BACKUP MODULE]: Not backing up region " + scene.RegionInfo.RegionName + " because its status is " + scene.RegionStatus.ToString ());
+				return;
+			}
+			
 			AutoBackupModuleState state = states[scene];
 			IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule> ();
 			string savePath = BuildOarPath (scene.RegionInfo.RegionName, state.GetBackupDir (), state.GetNamingType ());
@@ -454,9 +471,49 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
 			return uniqueFile.FullName;
 		}
 
-		private bool RunHeuristics ()
+		/*
+		 * Return value of true ==> not too busy; false ==> too busy to backup an OAR right now, or error.
+		 * */
+		private bool RunHeuristics (IScene region)
+		{
+			try {
+				return RunTimeDilationHeuristic (region) && RunAgentLimitHeuristic (region);
+			} catch (Exception e) {
+				m_log.Warn ("[AUTO BACKUP MODULE]: Exception in RunHeuristics", e);
+				return false;
+			}
+		}
+
+		/*
+		 * If the time dilation right at this instant is less than the threshold specified in AutoBackupDilationThreshold (default 0.5),
+		 * then we return false and trip the busy heuristic's "too busy" path (i.e. don't save an OAR).
+		 * AutoBackupDilationThreshold is a _LOWER BOUND_. Lower Time Dilation is bad, so if you go lower than our threshold, it's "too busy".
+		 * Return value of "true" ==> not too busy. Return value of "false" ==> too busy!
+		 * */
+		private bool RunTimeDilationHeuristic (IScene region)
 		{
-			return true;
+			string regionName = region.RegionInfo.RegionName;
+			return region.TimeDilation >= m_configSource.Configs["AutoBackupModule"].GetFloat (regionName + ".AutoBackupDilationThreshold", 0.5f);
+		}
+
+		/*
+		 * If the root agent count right at this instant is less than the threshold specified in AutoBackupAgentThreshold (default 10),
+		 * then we return false and trip the busy heuristic's "too busy" path (i.e., don't save an OAR).
+		 * AutoBackupAgentThreshold is an _UPPER BOUND_. Higher Agent Count is bad, so if you go higher than our threshold, it's "too busy".
+		 * Return value of "true" ==> not too busy. Return value of "false" ==> too busy!
+		 * */
+		private bool RunAgentLimitHeuristic (IScene region)
+		{
+			string regionName = region.RegionInfo.RegionName;
+			try {
+				Scene scene = (Scene)region;
+				//TODO: Why isn't GetRootAgentCount() a method in the IScene interface? Seems generally useful...
+				return scene.GetRootAgentCount () <= m_configSource.Configs["AutoBackupModule"].GetInt (regionName + ".AutoBackupAgentThreshold", 10);
+			} catch (InvalidCastException ice) {
+				m_log.Debug ("[AUTO BACKUP MODULE]: I NEED MAINTENANCE: IScene is not a Scene; can't get root agent count!");
+				return true;
+				//Non-obstructionist safest answer...
+			}
 		}
 
 		private void ExecuteScript (string scriptName, string savePath)
-- 
cgit v1.1