Be smarter about stopping timers. Cleanup formatting.

Use a boolean flag to tell timers that fire after IRegionModuleBase.Close() is called that they should not execute.
Also, I used MonoDevelop's auto-formatting feature to format the code uniformly. No guarantee about variable names though.
bulletsim
Sean McNamara 2011-02-28 11:04:54 -05:00
parent 34b6904939
commit a01c44e74d
1 changed files with 225 additions and 277 deletions

View File

@ -79,13 +79,12 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
TIME, TIME,
SEQUENTIAL, SEQUENTIAL,
OVERWRITE OVERWRITE
}; }
public class AutoBackupModule : ISharedRegionModule, IRegionModuleBase public class AutoBackupModule : ISharedRegionModule, IRegionModuleBase
{ {
private static readonly ILog m_log = private static readonly ILog m_log = LogManager.GetLogger (MethodBase.GetCurrentMethod ().DeclaringType);
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//AutoBackupModuleState: Auto-Backup state for one region (scene). //AutoBackupModuleState: Auto-Backup state for one region (scene).
public class AutoBackupModuleState public class AutoBackupModuleState
@ -98,70 +97,70 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
private string m_script = null; private string m_script = null;
private string m_dir = "."; private string m_dir = ".";
public AutoBackupModuleState(IScene scene) public AutoBackupModuleState (IScene scene)
{ {
m_scene = scene; m_scene = scene;
if(scene == null) if (scene == null)
throw new NullReferenceException("Required parameter missing for AutoBackupModuleState constructor"); throw new NullReferenceException ("Required parameter missing for AutoBackupModuleState constructor");
} }
public void SetEnabled(bool b) public void SetEnabled (bool b)
{ {
m_enabled = b; m_enabled = b;
} }
public bool GetEnabled() public bool GetEnabled ()
{ {
return m_enabled; return m_enabled;
} }
public Timer GetTimer() public Timer GetTimer ()
{ {
return m_timer; return m_timer;
} }
public void SetTimer(Timer t) public void SetTimer (Timer t)
{ {
m_timer = t; m_timer = t;
} }
public bool GetBusyCheck() public bool GetBusyCheck ()
{ {
return m_busycheck; return m_busycheck;
} }
public void SetBusyCheck(bool b) public void SetBusyCheck (bool b)
{ {
m_busycheck = b; m_busycheck = b;
} }
public string GetScript() public string GetScript ()
{ {
return m_script; return m_script;
} }
public void SetScript(string s) public void SetScript (string s)
{ {
m_script = s; m_script = s;
} }
public string GetBackupDir() public string GetBackupDir ()
{ {
return m_dir; return m_dir;
} }
public void SetBackupDir(string s) public void SetBackupDir (string s)
{ {
m_dir = s; m_dir = s;
} }
public NamingType GetNamingType() public NamingType GetNamingType ()
{ {
return m_naming; return m_naming;
} }
public void SetNamingType(NamingType n) public void SetNamingType (NamingType n)
{ {
m_naming = n; m_naming = n;
} }
@ -169,12 +168,15 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
//Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions. //Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions.
//Also helps if you don't want AutoBackup at all //Also helps if you don't want AutoBackup at all
readonly Dictionary<IScene, AutoBackupModuleState> states = new Dictionary<IScene, AutoBackupModuleState>(4); readonly Dictionary<IScene, AutoBackupModuleState> states = new Dictionary<IScene, AutoBackupModuleState> (4);
readonly Dictionary<double, Timer> timers = new Dictionary<double, Timer>(1); readonly Dictionary<double, Timer> timers = new Dictionary<double, Timer> (1);
readonly Dictionary<Timer, List<IScene>> timerMap = new Dictionary<Timer, List<IScene>>(1); readonly Dictionary<Timer, List<IScene>> timerMap = new Dictionary<Timer, List<IScene>> (1);
private IConfigSource m_configSource = null; private IConfigSource m_configSource = null;
private bool m_Enabled = false; //Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! private bool m_Enabled = false;
//Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState!
private bool m_closed = false;
//True means IRegionModuleBase.Close() was called on us, and we should stop operation ASAP.
//Used to prevent elapsing timers after Close() is called from trying to start an autobackup while the sim is shutting down.
public AutoBackupModule () public AutoBackupModule ()
{ {
@ -186,23 +188,21 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
//Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module //Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module
m_configSource = source; m_configSource = source;
IConfig moduleConfig = source.Configs["Modules"]; IConfig moduleConfig = source.Configs["Modules"];
if (moduleConfig != null) if (moduleConfig != null) {
{ m_Enabled = moduleConfig.GetBoolean ("AutoBackupModule", false);
m_Enabled = moduleConfig.GetBoolean("AutoBackupModule", false); if (m_Enabled) {
if (m_Enabled) m_log.Info ("[AUTO BACKUP MODULE]: AutoBackupModule enabled");
{
m_log.Info("[AUTO BACKUP MODULE]: AutoBackupModule enabled");
} }
} }
} }
void IRegionModuleBase.Close () void IRegionModuleBase.Close ()
{ {
if(!m_Enabled) if (!m_Enabled)
return; return;
//We don't want any timers firing while the sim's coming down; strange things may happen. //We don't want any timers firing while the sim's coming down; strange things may happen.
StopAllTimers(); StopAllTimers ();
} }
void IRegionModuleBase.AddRegion (Framework.Scenes.Scene scene) void IRegionModuleBase.AddRegion (Framework.Scenes.Scene scene)
@ -212,195 +212,161 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
void IRegionModuleBase.RemoveRegion (Framework.Scenes.Scene scene) void IRegionModuleBase.RemoveRegion (Framework.Scenes.Scene scene)
{ {
if(!m_Enabled) if (!m_Enabled)
return; return;
AutoBackupModuleState abms = states[scene]; AutoBackupModuleState abms = states[scene];
Timer timer = abms.GetTimer(); Timer timer = abms.GetTimer ();
List<IScene> list = timerMap[timer]; List<IScene> list = timerMap[timer];
list.Remove(scene); list.Remove (scene);
if(list.Count == 0) if (list.Count == 0) {
{ timerMap.Remove (timer);
timerMap.Remove(timer); timers.Remove (timer.Interval);
timers.Remove(timer.Interval); timer.Close ();
timer.Close();
} }
} }
void IRegionModuleBase.RegionLoaded (Framework.Scenes.Scene scene) void IRegionModuleBase.RegionLoaded (Framework.Scenes.Scene scene)
{ {
if(!m_Enabled) if (!m_Enabled)
return; return;
//This really ought not to happen, but just in case, let's pretend it didn't... //This really ought not to happen, but just in case, let's pretend it didn't...
if(scene == null) if (scene == null)
return; return;
string sRegionName = scene.RegionInfo.RegionName; string sRegionName = scene.RegionInfo.RegionName;
AutoBackupModuleState st = new AutoBackupModuleState(scene); AutoBackupModuleState st = new AutoBackupModuleState (scene);
states.Add(scene, st); states.Add (scene, st);
//Read the config settings and set variables. //Read the config settings and set variables.
IConfig config = m_configSource.Configs["AutoBackupModule"]; IConfig config = m_configSource.Configs["AutoBackupModule"];
if(config == null) if (config == null) {
{
//No config settings for any regions, let's just give up. //No config settings for any regions, let's just give up.
st.SetEnabled(false); st.SetEnabled (false);
m_log.Info("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled."); m_log.Info ("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled.");
return; return;
} }
st.SetEnabled(config.GetBoolean(sRegionName + ".AutoBackup", false)); st.SetEnabled (config.GetBoolean (sRegionName + ".AutoBackup", false));
if(!st.GetEnabled()) //If you don't want AutoBackup, we stop. //If you don't want AutoBackup, we stop.
{ if (!st.GetEnabled ()) {
m_log.Info("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled."); m_log.Info ("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled.");
return; return;
} } else {
else m_log.Info ("[AUTO BACKUP MODULE]: Region " + sRegionName + " is AutoBackup ENABLED.");
{
m_log.Info("[AUTO BACKUP MODULE]: Region " + sRegionName + " is AutoBackup ENABLED.");
} }
//Borrow an existing timer if one exists for the same interval; otherwise, make a new one. //Borrow an existing timer if one exists for the same interval; otherwise, make a new one.
double interval = config.GetDouble(sRegionName + ".AutoBackupInterval", 720) * 60000; double interval = config.GetDouble (sRegionName + ".AutoBackupInterval", 720) * 60000;
if(timers.ContainsKey(interval)) if (timers.ContainsKey (interval)) {
{ st.SetTimer (timers[interval]);
st.SetTimer(timers[interval]); m_log.Debug ("[AUTO BACKUP MODULE]: Reusing timer for " + interval + " msec for region " + sRegionName);
m_log.Debug("[AUTO BACKUP MODULE]: Reusing timer for " + interval + " msec for region " + sRegionName); } else {
}
else
{
//0 or negative interval == do nothing. //0 or negative interval == do nothing.
if(interval <= 0.0) if (interval <= 0.0) {
{ st.SetEnabled (false);
st.SetEnabled(false);
return; return;
} }
Timer tim = new Timer(interval); Timer tim = new Timer (interval);
st.SetTimer(tim); //Milliseconds -> minutes st.SetTimer (tim);
timers.Add(interval, tim); //Milliseconds -> minutes
timers.Add (interval, tim);
tim.Elapsed += HandleElapsed; tim.Elapsed += HandleElapsed;
tim.AutoReset = true; tim.AutoReset = true;
tim.Start(); tim.Start ();
//m_log.Debug("[AUTO BACKUP MODULE]: New timer for " + interval + " msec for region " + sRegionName); //m_log.Debug("[AUTO BACKUP MODULE]: New timer for " + interval + " msec for region " + sRegionName);
} }
//Add the current region to the list of regions tied to this timer. //Add the current region to the list of regions tied to this timer.
if(timerMap.ContainsKey(st.GetTimer())) if (timerMap.ContainsKey (st.GetTimer ())) {
{ timerMap[st.GetTimer ()].Add (scene);
timerMap[st.GetTimer()].Add(scene); } else {
} List<IScene> scns = new List<IScene> (1);
else scns.Add (scene);
{ timerMap.Add (st.GetTimer (), scns);
List<IScene> scns = new List<IScene>(1);
scns.Add(scene);
timerMap.Add(st.GetTimer(), scns);
} }
st.SetBusyCheck(config.GetBoolean(sRegionName + ".AutoBackupBusyCheck", true)); st.SetBusyCheck (config.GetBoolean (sRegionName + ".AutoBackupBusyCheck", true));
//Set file naming algorithm //Set file naming algorithm
string namingtype = config.GetString(sRegionName + ".AutoBackupNaming", "Time"); string namingtype = config.GetString (sRegionName + ".AutoBackupNaming", "Time");
if(namingtype.Equals("Time", StringComparison.CurrentCultureIgnoreCase)) if (namingtype.Equals ("Time", StringComparison.CurrentCultureIgnoreCase)) {
{ st.SetNamingType (NamingType.TIME);
st.SetNamingType(NamingType.TIME); } else if (namingtype.Equals ("Sequential", StringComparison.CurrentCultureIgnoreCase)) {
} st.SetNamingType (NamingType.SEQUENTIAL);
else if(namingtype.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase)) } else if (namingtype.Equals ("Overwrite", StringComparison.CurrentCultureIgnoreCase)) {
{ st.SetNamingType (NamingType.OVERWRITE);
st.SetNamingType(NamingType.SEQUENTIAL); } else {
} m_log.Warn ("Unknown naming type specified for region " + scene.RegionInfo.RegionName + ": " + namingtype);
else if(namingtype.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase)) st.SetNamingType (NamingType.TIME);
{
st.SetNamingType(NamingType.OVERWRITE);
}
else
{
m_log.Warn("Unknown naming type specified for region " + scene.RegionInfo.RegionName + ": " + namingtype);
st.SetNamingType(NamingType.TIME);
} }
st.SetScript(config.GetString(sRegionName + ".AutoBackupScript", null)); st.SetScript (config.GetString (sRegionName + ".AutoBackupScript", null));
st.SetBackupDir(config.GetString(sRegionName + ".AutoBackupDir", ".")); st.SetBackupDir (config.GetString (sRegionName + ".AutoBackupDir", "."));
//Let's give the user *one* convenience and auto-mkdir //Let's give the user *one* convenience and auto-mkdir
if(st.GetBackupDir() != ".") if (st.GetBackupDir () != ".") {
{ try {
try DirectoryInfo dirinfo = new DirectoryInfo (st.GetBackupDir ());
{ if (!dirinfo.Exists) {
DirectoryInfo dirinfo = new DirectoryInfo(st.GetBackupDir()); dirinfo.Create ();
if(!dirinfo.Exists)
{
dirinfo.Create();
} }
} } catch (Exception e) {
catch(Exception e) m_log.Warn ("BAD NEWS. You won't be able to save backups to directory " + st.GetBackupDir () + " because it doesn't exist or there's a permissions issue with it. Here's the exception.", e);
{
m_log.Warn("BAD NEWS. You won't be able to save backups to directory " + st.GetBackupDir() +
" because it doesn't exist or there's a permissions issue with it. Here's the exception.", e);
} }
} }
} }
void HandleElapsed (object sender, ElapsedEventArgs e) void HandleElapsed (object sender, ElapsedEventArgs e)
{ {
if (m_closed)
return;
bool heuristicsRun = false; bool heuristicsRun = false;
bool heuristicsPassed = false; bool heuristicsPassed = false;
if(!timerMap.ContainsKey((Timer) sender)) if (!timerMap.ContainsKey ((Timer)sender)) {
{ m_log.Debug ("Code-up error: timerMap doesn't contain timer " + sender.ToString ());
m_log.Debug("Code-up error: timerMap doesn't contain timer " + sender.ToString());
} }
foreach(IScene scene in timerMap[(Timer)sender]) foreach (IScene scene in timerMap[(Timer)sender]) {
{
AutoBackupModuleState state = states[scene]; AutoBackupModuleState state = states[scene];
bool heuristics = state.GetBusyCheck(); bool heuristics = state.GetBusyCheck ();
//Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region. //Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region.
if((heuristics && heuristicsRun && heuristicsPassed) if ((heuristics && heuristicsRun && heuristicsPassed) || !heuristics) {
|| !heuristics) doRegionBackup (scene);
{
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) } else if (heuristics && heuristicsRun && !heuristicsPassed) {
{
continue; continue;
}
//Logical Deduction: heuristics are on but haven't been run //Logical Deduction: heuristics are on but haven't been run
else } else {
{ heuristicsPassed = RunHeuristics ();
heuristicsPassed = RunHeuristics();
heuristicsRun = true; heuristicsRun = true;
if(!heuristicsPassed) if (!heuristicsPassed)
continue; continue;
doRegionBackup(scene); doRegionBackup (scene);
} }
} }
} }
void doRegionBackup(IScene scene) void doRegionBackup (IScene scene)
{ {
AutoBackupModuleState state = states[scene]; AutoBackupModuleState state = states[scene];
IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule>(); IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule> ();
string savePath = BuildOarPath(scene.RegionInfo.RegionName, state.GetBackupDir(), state.GetNamingType()); string savePath = BuildOarPath (scene.RegionInfo.RegionName, state.GetBackupDir (), state.GetNamingType ());
//m_log.Debug("[AUTO BACKUP MODULE]: savePath = " + savePath); //m_log.Debug("[AUTO BACKUP MODULE]: savePath = " + savePath);
if(savePath == null) if (savePath == null) {
{ m_log.Warn ("[AUTO BACKUP MODULE]: savePath is null in HandleElapsed");
m_log.Warn("[AUTO BACKUP MODULE]: savePath is null in HandleElapsed");
return; return;
} }
iram.ArchiveRegion(savePath, null); iram.ArchiveRegion (savePath, null);
ExecuteScript(state.GetScript(), savePath); ExecuteScript (state.GetScript (), savePath);
} }
string IRegionModuleBase.Name { string IRegionModuleBase.Name {
get { get { return "AutoBackupModule"; }
return "AutoBackupModule";
}
} }
Type IRegionModuleBase.ReplaceableInterface { Type IRegionModuleBase.ReplaceableInterface {
get { get { return null; }
return null;
}
} }
#endregion #endregion
@ -413,27 +379,25 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
#endregion #endregion
//Is this even needed? //Is this even needed?
public bool IsSharedModule public bool IsSharedModule {
{
get { return true; } get { return true; }
} }
private string BuildOarPath(string regionName, string baseDir, NamingType naming) private string BuildOarPath (string regionName, string baseDir, NamingType naming)
{ {
FileInfo path = null; FileInfo path = null;
switch(naming) switch (naming) {
{
case NamingType.OVERWRITE: case NamingType.OVERWRITE:
path = new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName); path = new FileInfo (baseDir + Path.DirectorySeparatorChar + regionName);
return path.FullName; return path.FullName;
case NamingType.TIME: case NamingType.TIME:
path = new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName + GetTimeString() + ".oar"); path = new FileInfo (baseDir + Path.DirectorySeparatorChar + regionName + GetTimeString () + ".oar");
return path.FullName; return path.FullName;
case NamingType.SEQUENTIAL: case NamingType.SEQUENTIAL:
path = new FileInfo(GetNextFile(baseDir, regionName)); path = new FileInfo (GetNextFile (baseDir, regionName));
return path.FullName; return path.FullName;
default: default:
m_log.Warn("VERY BAD: Unhandled case element " + naming.ToString()); m_log.Warn ("VERY BAD: Unhandled case element " + naming.ToString ());
break; break;
} }
@ -445,26 +409,26 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
//This format may turn out to be too unwieldy to keep... //This format may turn out to be too unwieldy to keep...
//Besides, that's what ctimes are for. But then how do I name each file uniquely without using a GUID? //Besides, that's what ctimes are for. But then how do I name each file uniquely without using a GUID?
//Sequential numbers, right? Ugh. Almost makes TOO much sense. //Sequential numbers, right? Ugh. Almost makes TOO much sense.
private string GetTimeString() private string GetTimeString ()
{ {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter ();
sw.Write("_"); sw.Write ("_");
DateTime now = DateTime.Now; DateTime now = DateTime.Now;
sw.Write(now.Year); sw.Write (now.Year);
sw.Write("y_"); sw.Write ("y_");
sw.Write(now.Month); sw.Write (now.Month);
sw.Write("M_"); sw.Write ("M_");
sw.Write(now.Day); sw.Write (now.Day);
sw.Write("d_"); sw.Write ("d_");
sw.Write(now.Hour); sw.Write (now.Hour);
sw.Write("h_"); sw.Write ("h_");
sw.Write(now.Minute); sw.Write (now.Minute);
sw.Write("m_"); sw.Write ("m_");
sw.Write(now.Second); sw.Write (now.Second);
sw.Write("s"); sw.Write ("s");
sw.Flush(); sw.Flush ();
string output = sw.ToString(); string output = sw.ToString ();
sw.Close(); sw.Close ();
return output; return output;
} }
@ -472,65 +436,60 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
//I really shouldn't put fields here, but for now.... ;) //I really shouldn't put fields here, but for now.... ;)
private string m_dirName = null; private string m_dirName = null;
private string m_regionName = null; private string m_regionName = null;
private string GetNextFile(string dirName, string regionName) private string GetNextFile (string dirName, string regionName)
{ {
FileInfo uniqueFile = null; FileInfo uniqueFile = null;
m_dirName = dirName; m_dirName = dirName;
m_regionName = regionName; m_regionName = regionName;
long biggestExistingFile = HalfIntervalMaximize(1, FileExistsTest); long biggestExistingFile = HalfIntervalMaximize (1, FileExistsTest);
biggestExistingFile++; //We don't want to overwrite the biggest existing file; we want to write to the NEXT biggest. biggestExistingFile++;
//We don't want to overwrite the biggest existing file; we want to write to the NEXT biggest.
uniqueFile = new FileInfo(m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + biggestExistingFile + ".oar"); uniqueFile = new FileInfo (m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + biggestExistingFile + ".oar");
if(uniqueFile.Exists) if (uniqueFile.Exists) {
{
//Congratulations, your strange deletion patterns fooled my half-interval search into picking an existing file! //Congratulations, your strange deletion patterns fooled my half-interval search into picking an existing file!
//Now you get to pay the performance cost :) //Now you get to pay the performance cost :)
uniqueFile = UniqueFileSearchLinear(biggestExistingFile); uniqueFile = UniqueFileSearchLinear (biggestExistingFile);
} }
return uniqueFile.FullName; return uniqueFile.FullName;
} }
private bool RunHeuristics() private bool RunHeuristics ()
{ {
return true; return true;
} }
private void ExecuteScript(string scriptName, string savePath) private void ExecuteScript (string scriptName, string savePath)
{ {
//Fast path out //Fast path out
if(scriptName == null || scriptName.Length <= 0) if (scriptName == null || scriptName.Length <= 0)
return; return;
try try {
{ FileInfo fi = new FileInfo (scriptName);
FileInfo fi = new FileInfo(scriptName); if (fi.Exists) {
if(fi.Exists) ProcessStartInfo psi = new ProcessStartInfo (scriptName);
{
ProcessStartInfo psi = new ProcessStartInfo(scriptName);
psi.Arguments = savePath; psi.Arguments = savePath;
psi.CreateNoWindow = true; psi.CreateNoWindow = true;
Process proc = Process.Start(psi); Process proc = Process.Start (psi);
proc.ErrorDataReceived += HandleProcErrorDataReceived; proc.ErrorDataReceived += HandleProcErrorDataReceived;
} }
} } catch (Exception e) {
catch(Exception e) m_log.Warn ("Exception encountered when trying to run script for oar backup " + savePath, e);
{
m_log.Warn("Exception encountered when trying to run script for oar backup " + savePath, e);
} }
} }
void HandleProcErrorDataReceived (object sender, DataReceivedEventArgs e) void HandleProcErrorDataReceived (object sender, DataReceivedEventArgs e)
{ {
m_log.Warn("ExecuteScript hook " + ((Process)sender).ProcessName + " is yacking on stderr: " + e.Data); m_log.Warn ("ExecuteScript hook " + ((Process)sender).ProcessName + " is yacking on stderr: " + e.Data);
} }
private void StopAllTimers() private void StopAllTimers ()
{ {
foreach(Timer t in timerMap.Keys) foreach (Timer t in timerMap.Keys) {
{ t.Close ();
t.Close();
} }
m_closed = true;
} }
/* Find the largest value for which the predicate returns true. /* Find the largest value for which the predicate returns true.
@ -542,65 +501,54 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
* And of course it is fantastic with powers of 2, which are densely packed in values under 100 anyway. * And of course it is fantastic with powers of 2, which are densely packed in values under 100 anyway.
* The Predicate<long> parameter must be a function that accepts a long and returns a bool. * The Predicate<long> parameter must be a function that accepts a long and returns a bool.
* */ * */
public long HalfIntervalMaximize(long start, Predicate<long> pred) public long HalfIntervalMaximize (long start, Predicate<long> pred)
{ {
long prev = start, curr = start, biggest = 0; long prev = start, curr = start, biggest = 0;
if(start < 0) if (start < 0)
throw new IndexOutOfRangeException("Start value for HalfIntervalMaximize must be non-negative"); throw new IndexOutOfRangeException ("Start value for HalfIntervalMaximize must be non-negative");
do do {
{ if (pred (curr)) {
if(pred(curr)) if (curr > biggest) {
{
if(curr > biggest)
{
biggest = curr; biggest = curr;
} }
prev = curr; prev = curr;
if(curr == 0) if (curr == 0) {
{
//Special case because 0 * 2 = 0 :) //Special case because 0 * 2 = 0 :)
curr = 1; curr = 1;
} } else {
else
{
//Look deeper //Look deeper
curr *= 2; curr *= 2;
} }
} } else {
else
{
// We went too far, back off halfway // We went too far, back off halfway
curr = (curr + prev) / 2; curr = (curr + prev) / 2;
} }
} } while (curr - prev > 0);
while(curr - prev > 0);
return biggest; return biggest;
} }
public bool FileExistsTest(long num) public bool FileExistsTest (long num)
{ {
FileInfo test = new FileInfo(m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + num + ".oar"); FileInfo test = new FileInfo (m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + num + ".oar");
return test.Exists; return test.Exists;
} }
//Very slow, hence why we try the HalfIntervalMaximize first! //Very slow, hence why we try the HalfIntervalMaximize first!
public FileInfo UniqueFileSearchLinear(long start) public FileInfo UniqueFileSearchLinear (long start)
{ {
long l = start; long l = start;
FileInfo retval = null; FileInfo retval = null;
do do {
{ retval = new FileInfo (m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + (l++) + ".oar");
retval = new FileInfo(m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + (l++) + ".oar"); } while (retval.Exists);
}
while(retval.Exists);
return retval; return retval;
} }
} }
} }