aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
diff options
context:
space:
mode:
authorSean McNamara2011-02-28 11:04:54 -0500
committerSean McNamara2011-02-28 11:04:54 -0500
commita01c44e74de669ea2643b8bfe76a7e78ca4740a4 (patch)
tree96a58146213ef9561d45515c9146ac78a3f89791 /OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
parentFirst working commit of AutoBackupModule. (diff)
downloadopensim-SC-a01c44e74de669ea2643b8bfe76a7e78ca4740a4.zip
opensim-SC-a01c44e74de669ea2643b8bfe76a7e78ca4740a4.tar.gz
opensim-SC-a01c44e74de669ea2643b8bfe76a7e78ca4740a4.tar.bz2
opensim-SC-a01c44e74de669ea2643b8bfe76a7e78ca4740a4.tar.xz
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.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs502
1 files changed, 225 insertions, 277 deletions
diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
index e3686ac..54b9b09 100644
--- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
+++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs
@@ -73,20 +73,19 @@ using OpenSim.Region.Framework.Interfaces;
73 73
74namespace OpenSim.Region.OptionalModules.World.AutoBackup 74namespace OpenSim.Region.OptionalModules.World.AutoBackup
75{ 75{
76 76
77 public enum NamingType 77 public enum NamingType
78 { 78 {
79 TIME, 79 TIME,
80 SEQUENTIAL, 80 SEQUENTIAL,
81 OVERWRITE 81 OVERWRITE
82 }; 82 }
83 83
84 public class AutoBackupModule : ISharedRegionModule, IRegionModuleBase 84 public class AutoBackupModule : ISharedRegionModule, IRegionModuleBase
85 { 85 {
86 86
87 private static readonly ILog m_log = 87 private static readonly ILog m_log = LogManager.GetLogger (MethodBase.GetCurrentMethod ().DeclaringType);
88 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 88
89
90 //AutoBackupModuleState: Auto-Backup state for one region (scene). 89 //AutoBackupModuleState: Auto-Backup state for one region (scene).
91 public class AutoBackupModuleState 90 public class AutoBackupModuleState
92 { 91 {
@@ -97,84 +96,87 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
97 private bool m_busycheck = true; 96 private bool m_busycheck = true;
98 private string m_script = null; 97 private string m_script = null;
99 private string m_dir = "."; 98 private string m_dir = ".";
100 99
101 public AutoBackupModuleState(IScene scene) 100 public AutoBackupModuleState (IScene scene)
102 { 101 {
103 m_scene = scene; 102 m_scene = scene;
104 if(scene == null) 103 if (scene == null)
105 throw new NullReferenceException("Required parameter missing for AutoBackupModuleState constructor"); 104 throw new NullReferenceException ("Required parameter missing for AutoBackupModuleState constructor");
106 } 105 }
107 106
108 public void SetEnabled(bool b) 107 public void SetEnabled (bool b)
109 { 108 {
110 m_enabled = b; 109 m_enabled = b;
111 } 110 }
112 111
113 public bool GetEnabled() 112 public bool GetEnabled ()
114 { 113 {
115 return m_enabled; 114 return m_enabled;
116 } 115 }
117 116
118 public Timer GetTimer() 117 public Timer GetTimer ()
119 { 118 {
120 return m_timer; 119 return m_timer;
121 } 120 }
122 121
123 public void SetTimer(Timer t) 122 public void SetTimer (Timer t)
124 { 123 {
125 m_timer = t; 124 m_timer = t;
126 } 125 }
127 126
128 public bool GetBusyCheck() 127 public bool GetBusyCheck ()
129 { 128 {
130 return m_busycheck; 129 return m_busycheck;
131 } 130 }
132 131
133 public void SetBusyCheck(bool b) 132 public void SetBusyCheck (bool b)
134 { 133 {
135 m_busycheck = b; 134 m_busycheck = b;
136 } 135 }
137 136
138 137
139 public string GetScript() 138 public string GetScript ()
140 { 139 {
141 return m_script; 140 return m_script;
142 } 141 }
143 142
144 public void SetScript(string s) 143 public void SetScript (string s)
145 { 144 {
146 m_script = s; 145 m_script = s;
147 } 146 }
148 147
149 public string GetBackupDir() 148 public string GetBackupDir ()
150 { 149 {
151 return m_dir; 150 return m_dir;
152 } 151 }
153 152
154 public void SetBackupDir(string s) 153 public void SetBackupDir (string s)
155 { 154 {
156 m_dir = s; 155 m_dir = s;
157 } 156 }
158 157
159 public NamingType GetNamingType() 158 public NamingType GetNamingType ()
160 { 159 {
161 return m_naming; 160 return m_naming;
162 } 161 }
163 162
164 public void SetNamingType(NamingType n) 163 public void SetNamingType (NamingType n)
165 { 164 {
166 m_naming = n; 165 m_naming = n;
167 } 166 }
168 } 167 }
169 168
170 //Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions. 169 //Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions.
171 //Also helps if you don't want AutoBackup at all 170 //Also helps if you don't want AutoBackup at all
172 readonly Dictionary<IScene, AutoBackupModuleState> states = new Dictionary<IScene, AutoBackupModuleState>(4); 171 readonly Dictionary<IScene, AutoBackupModuleState> states = new Dictionary<IScene, AutoBackupModuleState> (4);
173 readonly Dictionary<double, Timer> timers = new Dictionary<double, Timer>(1); 172 readonly Dictionary<double, Timer> timers = new Dictionary<double, Timer> (1);
174 readonly Dictionary<Timer, List<IScene>> timerMap = new Dictionary<Timer, List<IScene>>(1); 173 readonly Dictionary<Timer, List<IScene>> timerMap = new Dictionary<Timer, List<IScene>> (1);
175 private IConfigSource m_configSource = null; 174 private IConfigSource m_configSource = null;
176 private bool m_Enabled = false; //Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! 175 private bool m_Enabled = false;
177 176 //Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState!
177 private bool m_closed = false;
178 //True means IRegionModuleBase.Close() was called on us, and we should stop operation ASAP.
179 //Used to prevent elapsing timers after Close() is called from trying to start an autobackup while the sim is shutting down.
178 public AutoBackupModule () 180 public AutoBackupModule ()
179 { 181 {
180 182
@@ -185,24 +187,22 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
185 { 187 {
186 //Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module 188 //Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module
187 m_configSource = source; 189 m_configSource = source;
188 IConfig moduleConfig = source.Configs["Modules"]; 190 IConfig moduleConfig = source.Configs["Modules"];
189 if (moduleConfig != null) 191 if (moduleConfig != null) {
190 { 192 m_Enabled = moduleConfig.GetBoolean ("AutoBackupModule", false);
191 m_Enabled = moduleConfig.GetBoolean("AutoBackupModule", false); 193 if (m_Enabled) {
192 if (m_Enabled) 194 m_log.Info ("[AUTO BACKUP MODULE]: AutoBackupModule enabled");
193 { 195 }
194 m_log.Info("[AUTO BACKUP MODULE]: AutoBackupModule enabled"); 196 }
195 }
196 }
197 } 197 }
198 198
199 void IRegionModuleBase.Close () 199 void IRegionModuleBase.Close ()
200 { 200 {
201 if(!m_Enabled) 201 if (!m_Enabled)
202 return; 202 return;
203 203
204 //We don't want any timers firing while the sim's coming down; strange things may happen. 204 //We don't want any timers firing while the sim's coming down; strange things may happen.
205 StopAllTimers(); 205 StopAllTimers ();
206 } 206 }
207 207
208 void IRegionModuleBase.AddRegion (Framework.Scenes.Scene scene) 208 void IRegionModuleBase.AddRegion (Framework.Scenes.Scene scene)
@@ -212,327 +212,286 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
212 212
213 void IRegionModuleBase.RemoveRegion (Framework.Scenes.Scene scene) 213 void IRegionModuleBase.RemoveRegion (Framework.Scenes.Scene scene)
214 { 214 {
215 if(!m_Enabled) 215 if (!m_Enabled)
216 return; 216 return;
217 217
218 AutoBackupModuleState abms = states[scene]; 218 AutoBackupModuleState abms = states[scene];
219 Timer timer = abms.GetTimer(); 219 Timer timer = abms.GetTimer ();
220 List<IScene> list = timerMap[timer]; 220 List<IScene> list = timerMap[timer];
221 list.Remove(scene); 221 list.Remove (scene);
222 if(list.Count == 0) 222 if (list.Count == 0) {
223 { 223 timerMap.Remove (timer);
224 timerMap.Remove(timer); 224 timers.Remove (timer.Interval);
225 timers.Remove(timer.Interval); 225 timer.Close ();
226 timer.Close();
227 } 226 }
228 } 227 }
229 228
230 void IRegionModuleBase.RegionLoaded (Framework.Scenes.Scene scene) 229 void IRegionModuleBase.RegionLoaded (Framework.Scenes.Scene scene)
231 { 230 {
232 if(!m_Enabled) 231 if (!m_Enabled)
233 return; 232 return;
234 233
235 //This really ought not to happen, but just in case, let's pretend it didn't... 234 //This really ought not to happen, but just in case, let's pretend it didn't...
236 if(scene == null) 235 if (scene == null)
237 return; 236 return;
238 237
239 string sRegionName = scene.RegionInfo.RegionName; 238 string sRegionName = scene.RegionInfo.RegionName;
240 AutoBackupModuleState st = new AutoBackupModuleState(scene); 239 AutoBackupModuleState st = new AutoBackupModuleState (scene);
241 states.Add(scene, st); 240 states.Add (scene, st);
242 241
243 //Read the config settings and set variables. 242 //Read the config settings and set variables.
244 IConfig config = m_configSource.Configs["AutoBackupModule"]; 243 IConfig config = m_configSource.Configs["AutoBackupModule"];
245 if(config == null) 244 if (config == null) {
246 {
247 //No config settings for any regions, let's just give up. 245 //No config settings for any regions, let's just give up.
248 st.SetEnabled(false); 246 st.SetEnabled (false);
249 m_log.Info("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled."); 247 m_log.Info ("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled.");
250 return; 248 return;
251 } 249 }
252 st.SetEnabled(config.GetBoolean(sRegionName + ".AutoBackup", false)); 250 st.SetEnabled (config.GetBoolean (sRegionName + ".AutoBackup", false));
253 if(!st.GetEnabled()) //If you don't want AutoBackup, we stop. 251 //If you don't want AutoBackup, we stop.
254 { 252 if (!st.GetEnabled ()) {
255 m_log.Info("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled."); 253 m_log.Info ("[AUTO BACKUP MODULE]: Region " + sRegionName + " is NOT AutoBackup enabled.");
256 return; 254 return;
257 } 255 } else {
258 else 256 m_log.Info ("[AUTO BACKUP MODULE]: Region " + sRegionName + " is AutoBackup ENABLED.");
259 {
260 m_log.Info("[AUTO BACKUP MODULE]: Region " + sRegionName + " is AutoBackup ENABLED.");
261 } 257 }
262 258
263 //Borrow an existing timer if one exists for the same interval; otherwise, make a new one. 259 //Borrow an existing timer if one exists for the same interval; otherwise, make a new one.
264 double interval = config.GetDouble(sRegionName + ".AutoBackupInterval", 720) * 60000; 260 double interval = config.GetDouble (sRegionName + ".AutoBackupInterval", 720) * 60000;
265 if(timers.ContainsKey(interval)) 261 if (timers.ContainsKey (interval)) {
266 { 262 st.SetTimer (timers[interval]);
267 st.SetTimer(timers[interval]); 263 m_log.Debug ("[AUTO BACKUP MODULE]: Reusing timer for " + interval + " msec for region " + sRegionName);
268 m_log.Debug("[AUTO BACKUP MODULE]: Reusing timer for " + interval + " msec for region " + sRegionName); 264 } else {
269 }
270 else
271 {
272 //0 or negative interval == do nothing. 265 //0 or negative interval == do nothing.
273 if(interval <= 0.0) 266 if (interval <= 0.0) {
274 { 267 st.SetEnabled (false);
275 st.SetEnabled(false);
276 return; 268 return;
277 } 269 }
278 Timer tim = new Timer(interval); 270 Timer tim = new Timer (interval);
279 st.SetTimer(tim); //Milliseconds -> minutes 271 st.SetTimer (tim);
280 timers.Add(interval, tim); 272 //Milliseconds -> minutes
281 tim.Elapsed += HandleElapsed; 273 timers.Add (interval, tim);
274 tim.Elapsed += HandleElapsed;
282 tim.AutoReset = true; 275 tim.AutoReset = true;
283 tim.Start(); 276 tim.Start ();
284 //m_log.Debug("[AUTO BACKUP MODULE]: New timer for " + interval + " msec for region " + sRegionName); 277 //m_log.Debug("[AUTO BACKUP MODULE]: New timer for " + interval + " msec for region " + sRegionName);
285 } 278 }
286 279
287 //Add the current region to the list of regions tied to this timer. 280 //Add the current region to the list of regions tied to this timer.
288 if(timerMap.ContainsKey(st.GetTimer())) 281 if (timerMap.ContainsKey (st.GetTimer ())) {
289 { 282 timerMap[st.GetTimer ()].Add (scene);
290 timerMap[st.GetTimer()].Add(scene); 283 } else {
291 } 284 List<IScene> scns = new List<IScene> (1);
292 else 285 scns.Add (scene);
293 { 286 timerMap.Add (st.GetTimer (), scns);
294 List<IScene> scns = new List<IScene>(1);
295 scns.Add(scene);
296 timerMap.Add(st.GetTimer(), scns);
297 } 287 }
298 288
299 st.SetBusyCheck(config.GetBoolean(sRegionName + ".AutoBackupBusyCheck", true)); 289 st.SetBusyCheck (config.GetBoolean (sRegionName + ".AutoBackupBusyCheck", true));
300 290
301 //Set file naming algorithm 291 //Set file naming algorithm
302 string namingtype = config.GetString(sRegionName + ".AutoBackupNaming", "Time"); 292 string namingtype = config.GetString (sRegionName + ".AutoBackupNaming", "Time");
303 if(namingtype.Equals("Time", StringComparison.CurrentCultureIgnoreCase)) 293 if (namingtype.Equals ("Time", StringComparison.CurrentCultureIgnoreCase)) {
304 { 294 st.SetNamingType (NamingType.TIME);
305 st.SetNamingType(NamingType.TIME); 295 } else if (namingtype.Equals ("Sequential", StringComparison.CurrentCultureIgnoreCase)) {
306 } 296 st.SetNamingType (NamingType.SEQUENTIAL);
307 else if(namingtype.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase)) 297 } else if (namingtype.Equals ("Overwrite", StringComparison.CurrentCultureIgnoreCase)) {
308 { 298 st.SetNamingType (NamingType.OVERWRITE);
309 st.SetNamingType(NamingType.SEQUENTIAL); 299 } else {
310 } 300 m_log.Warn ("Unknown naming type specified for region " + scene.RegionInfo.RegionName + ": " + namingtype);
311 else if(namingtype.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase)) 301 st.SetNamingType (NamingType.TIME);
312 {
313 st.SetNamingType(NamingType.OVERWRITE);
314 }
315 else
316 {
317 m_log.Warn("Unknown naming type specified for region " + scene.RegionInfo.RegionName + ": " + namingtype);
318 st.SetNamingType(NamingType.TIME);
319 } 302 }
320 303
321 st.SetScript(config.GetString(sRegionName + ".AutoBackupScript", null)); 304 st.SetScript (config.GetString (sRegionName + ".AutoBackupScript", null));
322 st.SetBackupDir(config.GetString(sRegionName + ".AutoBackupDir", ".")); 305 st.SetBackupDir (config.GetString (sRegionName + ".AutoBackupDir", "."));
323 306
324 //Let's give the user *one* convenience and auto-mkdir 307 //Let's give the user *one* convenience and auto-mkdir
325 if(st.GetBackupDir() != ".") 308 if (st.GetBackupDir () != ".") {
326 { 309 try {
327 try 310 DirectoryInfo dirinfo = new DirectoryInfo (st.GetBackupDir ());
328 { 311 if (!dirinfo.Exists) {
329 DirectoryInfo dirinfo = new DirectoryInfo(st.GetBackupDir()); 312 dirinfo.Create ();
330 if(!dirinfo.Exists)
331 {
332 dirinfo.Create();
333 } 313 }
334 } 314 } catch (Exception e) {
335 catch(Exception e) 315 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);
336 {
337 m_log.Warn("BAD NEWS. You won't be able to save backups to directory " + st.GetBackupDir() +
338 " because it doesn't exist or there's a permissions issue with it. Here's the exception.", e);
339 } 316 }
340 } 317 }
341 } 318 }
342 319
343 void HandleElapsed (object sender, ElapsedEventArgs e) 320 void HandleElapsed (object sender, ElapsedEventArgs e)
344 { 321 {
322 if (m_closed)
323 return;
345 bool heuristicsRun = false; 324 bool heuristicsRun = false;
346 bool heuristicsPassed = false; 325 bool heuristicsPassed = false;
347 if(!timerMap.ContainsKey((Timer) sender)) 326 if (!timerMap.ContainsKey ((Timer)sender)) {
348 { 327 m_log.Debug ("Code-up error: timerMap doesn't contain timer " + sender.ToString ());
349 m_log.Debug("Code-up error: timerMap doesn't contain timer " + sender.ToString());
350 } 328 }
351 foreach(IScene scene in timerMap[(Timer)sender]) 329 foreach (IScene scene in timerMap[(Timer)sender]) {
352 {
353 AutoBackupModuleState state = states[scene]; 330 AutoBackupModuleState state = states[scene];
354 bool heuristics = state.GetBusyCheck(); 331 bool heuristics = state.GetBusyCheck ();
355 332
356 //Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region. 333 //Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region.
357 if((heuristics && heuristicsRun && heuristicsPassed) 334 if ((heuristics && heuristicsRun && heuristicsPassed) || !heuristics) {
358 || !heuristics) 335 doRegionBackup (scene);
359 {
360 doRegionBackup(scene);
361 }
362 //Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off! 336 //Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off!
363 else if(heuristics && heuristicsRun && !heuristicsPassed) 337 } else if (heuristics && heuristicsRun && !heuristicsPassed) {
364 {
365 continue; 338 continue;
366 }
367 //Logical Deduction: heuristics are on but haven't been run 339 //Logical Deduction: heuristics are on but haven't been run
368 else 340 } else {
369 { 341 heuristicsPassed = RunHeuristics ();
370 heuristicsPassed = RunHeuristics();
371 heuristicsRun = true; 342 heuristicsRun = true;
372 if(!heuristicsPassed) 343 if (!heuristicsPassed)
373 continue; 344 continue;
374 doRegionBackup(scene); 345 doRegionBackup (scene);
375 } 346 }
376 } 347 }
377 } 348 }
378 349
379 void doRegionBackup(IScene scene) 350 void doRegionBackup (IScene scene)
380 { 351 {
381 AutoBackupModuleState state = states[scene]; 352 AutoBackupModuleState state = states[scene];
382 IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule>(); 353 IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule> ();
383 string savePath = BuildOarPath(scene.RegionInfo.RegionName, state.GetBackupDir(), state.GetNamingType()); 354 string savePath = BuildOarPath (scene.RegionInfo.RegionName, state.GetBackupDir (), state.GetNamingType ());
384 //m_log.Debug("[AUTO BACKUP MODULE]: savePath = " + savePath); 355 //m_log.Debug("[AUTO BACKUP MODULE]: savePath = " + savePath);
385 if(savePath == null) 356 if (savePath == null) {
386 { 357 m_log.Warn ("[AUTO BACKUP MODULE]: savePath is null in HandleElapsed");
387 m_log.Warn("[AUTO BACKUP MODULE]: savePath is null in HandleElapsed");
388 return; 358 return;
389 } 359 }
390 iram.ArchiveRegion(savePath, null); 360 iram.ArchiveRegion (savePath, null);
391 ExecuteScript(state.GetScript(), savePath); 361 ExecuteScript (state.GetScript (), savePath);
392 } 362 }
393 363
394 string IRegionModuleBase.Name { 364 string IRegionModuleBase.Name {
395 get { 365 get { return "AutoBackupModule"; }
396 return "AutoBackupModule";
397 }
398 } 366 }
399 367
400 Type IRegionModuleBase.ReplaceableInterface { 368 Type IRegionModuleBase.ReplaceableInterface {
401 get { 369 get { return null; }
402 return null;
403 }
404 } 370 }
405 371
406 #endregion 372 #endregion
407 #region ISharedRegionModule implementation 373 #region ISharedRegionModule implementation
408 void ISharedRegionModule.PostInitialise () 374 void ISharedRegionModule.PostInitialise ()
409 { 375 {
410 //I don't care right now. 376 //I don't care right now.
411 } 377 }
412 378
413 #endregion 379 #endregion
414 380
415 //Is this even needed? 381 //Is this even needed?
416 public bool IsSharedModule 382 public bool IsSharedModule {
417 { 383 get { return true; }
418 get { return true; } 384 }
419 } 385
420 386 private string BuildOarPath (string regionName, string baseDir, NamingType naming)
421 private string BuildOarPath(string regionName, string baseDir, NamingType naming)
422 { 387 {
423 FileInfo path = null; 388 FileInfo path = null;
424 switch(naming) 389 switch (naming) {
425 {
426 case NamingType.OVERWRITE: 390 case NamingType.OVERWRITE:
427 path = new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName); 391 path = new FileInfo (baseDir + Path.DirectorySeparatorChar + regionName);
428 return path.FullName; 392 return path.FullName;
429 case NamingType.TIME: 393 case NamingType.TIME:
430 path = new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName + GetTimeString() + ".oar"); 394 path = new FileInfo (baseDir + Path.DirectorySeparatorChar + regionName + GetTimeString () + ".oar");
431 return path.FullName; 395 return path.FullName;
432 case NamingType.SEQUENTIAL: 396 case NamingType.SEQUENTIAL:
433 path = new FileInfo(GetNextFile(baseDir, regionName)); 397 path = new FileInfo (GetNextFile (baseDir, regionName));
434 return path.FullName; 398 return path.FullName;
435 default: 399 default:
436 m_log.Warn("VERY BAD: Unhandled case element " + naming.ToString()); 400 m_log.Warn ("VERY BAD: Unhandled case element " + naming.ToString ());
437 break; 401 break;
438 } 402 }
439 403
440 return path.FullName; 404 return path.FullName;
441 } 405 }
442 406
443 //Welcome to the TIME STRING. 4 CORNER INTEGERS, CUBES 4 QUAD MEMORY -- No 1 Integer God. 407 //Welcome to the TIME STRING. 4 CORNER INTEGERS, CUBES 4 QUAD MEMORY -- No 1 Integer God.
444 //(Terrible reference to <timecube.com>) 408 //(Terrible reference to <timecube.com>)
445 //This format may turn out to be too unwieldy to keep... 409 //This format may turn out to be too unwieldy to keep...
446 //Besides, that's what ctimes are for. But then how do I name each file uniquely without using a GUID? 410 //Besides, that's what ctimes are for. But then how do I name each file uniquely without using a GUID?
447 //Sequential numbers, right? Ugh. Almost makes TOO much sense. 411 //Sequential numbers, right? Ugh. Almost makes TOO much sense.
448 private string GetTimeString() 412 private string GetTimeString ()
449 { 413 {
450 StringWriter sw = new StringWriter(); 414 StringWriter sw = new StringWriter ();
451 sw.Write("_"); 415 sw.Write ("_");
452 DateTime now = DateTime.Now; 416 DateTime now = DateTime.Now;
453 sw.Write(now.Year); 417 sw.Write (now.Year);
454 sw.Write("y_"); 418 sw.Write ("y_");
455 sw.Write(now.Month); 419 sw.Write (now.Month);
456 sw.Write("M_"); 420 sw.Write ("M_");
457 sw.Write(now.Day); 421 sw.Write (now.Day);
458 sw.Write("d_"); 422 sw.Write ("d_");
459 sw.Write(now.Hour); 423 sw.Write (now.Hour);
460 sw.Write("h_"); 424 sw.Write ("h_");
461 sw.Write(now.Minute); 425 sw.Write (now.Minute);
462 sw.Write("m_"); 426 sw.Write ("m_");
463 sw.Write(now.Second); 427 sw.Write (now.Second);
464 sw.Write("s"); 428 sw.Write ("s");
465 sw.Flush(); 429 sw.Flush ();
466 string output = sw.ToString(); 430 string output = sw.ToString ();
467 sw.Close(); 431 sw.Close ();
468 return output; 432 return output;
469 } 433 }
470 434
471 //Get the next logical file name 435 //Get the next logical file name
472 //I really shouldn't put fields here, but for now.... ;) 436 //I really shouldn't put fields here, but for now.... ;)
473 private string m_dirName = null; 437 private string m_dirName = null;
474 private string m_regionName = null; 438 private string m_regionName = null;
475 private string GetNextFile(string dirName, string regionName) 439 private string GetNextFile (string dirName, string regionName)
476 { 440 {
477 FileInfo uniqueFile = null; 441 FileInfo uniqueFile = null;
478 m_dirName = dirName; 442 m_dirName = dirName;
479 m_regionName = regionName; 443 m_regionName = regionName;
480 long biggestExistingFile = HalfIntervalMaximize(1, FileExistsTest); 444 long biggestExistingFile = HalfIntervalMaximize (1, FileExistsTest);
481 biggestExistingFile++; //We don't want to overwrite the biggest existing file; we want to write to the NEXT biggest. 445 biggestExistingFile++;
482 446 //We don't want to overwrite the biggest existing file; we want to write to the NEXT biggest.
483 uniqueFile = new FileInfo(m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + biggestExistingFile + ".oar"); 447 uniqueFile = new FileInfo (m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + biggestExistingFile + ".oar");
484 if(uniqueFile.Exists) 448 if (uniqueFile.Exists) {
485 {
486 //Congratulations, your strange deletion patterns fooled my half-interval search into picking an existing file! 449 //Congratulations, your strange deletion patterns fooled my half-interval search into picking an existing file!
487 //Now you get to pay the performance cost :) 450 //Now you get to pay the performance cost :)
488 uniqueFile = UniqueFileSearchLinear(biggestExistingFile); 451 uniqueFile = UniqueFileSearchLinear (biggestExistingFile);
489 } 452 }
490 453
491 return uniqueFile.FullName; 454 return uniqueFile.FullName;
492 } 455 }
493 456
494 private bool RunHeuristics() 457 private bool RunHeuristics ()
495 { 458 {
496 return true; 459 return true;
497 } 460 }
498 461
499 private void ExecuteScript(string scriptName, string savePath) 462 private void ExecuteScript (string scriptName, string savePath)
500 { 463 {
501 //Fast path out 464 //Fast path out
502 if(scriptName == null || scriptName.Length <= 0) 465 if (scriptName == null || scriptName.Length <= 0)
503 return; 466 return;
504 467
505 try 468 try {
506 { 469 FileInfo fi = new FileInfo (scriptName);
507 FileInfo fi = new FileInfo(scriptName); 470 if (fi.Exists) {
508 if(fi.Exists) 471 ProcessStartInfo psi = new ProcessStartInfo (scriptName);
509 {
510 ProcessStartInfo psi = new ProcessStartInfo(scriptName);
511 psi.Arguments = savePath; 472 psi.Arguments = savePath;
512 psi.CreateNoWindow = true; 473 psi.CreateNoWindow = true;
513 Process proc = Process.Start(psi); 474 Process proc = Process.Start (psi);
514 proc.ErrorDataReceived += HandleProcErrorDataReceived; 475 proc.ErrorDataReceived += HandleProcErrorDataReceived;
515 } 476 }
516 } 477 } catch (Exception e) {
517 catch(Exception e) 478 m_log.Warn ("Exception encountered when trying to run script for oar backup " + savePath, e);
518 {
519 m_log.Warn("Exception encountered when trying to run script for oar backup " + savePath, e);
520 } 479 }
521 } 480 }
522 481
523 void HandleProcErrorDataReceived (object sender, DataReceivedEventArgs e) 482 void HandleProcErrorDataReceived (object sender, DataReceivedEventArgs e)
524 { 483 {
525 m_log.Warn("ExecuteScript hook " + ((Process)sender).ProcessName + " is yacking on stderr: " + e.Data); 484 m_log.Warn ("ExecuteScript hook " + ((Process)sender).ProcessName + " is yacking on stderr: " + e.Data);
526 } 485 }
527 486
528 private void StopAllTimers() 487 private void StopAllTimers ()
529 { 488 {
530 foreach(Timer t in timerMap.Keys) 489 foreach (Timer t in timerMap.Keys) {
531 { 490 t.Close ();
532 t.Close();
533 } 491 }
492 m_closed = true;
534 } 493 }
535 494
536 /* Find the largest value for which the predicate returns true. 495 /* Find the largest value for which the predicate returns true.
537 * We use a bisection algorithm (half interval) to make the algorithm scalable. 496 * We use a bisection algorithm (half interval) to make the algorithm scalable.
538 * The worst-case complexity is about O(log(n)^2) in practice. 497 * The worst-case complexity is about O(log(n)^2) in practice.
@@ -542,65 +501,54 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
542 * And of course it is fantastic with powers of 2, which are densely packed in values under 100 anyway. 501 * And of course it is fantastic with powers of 2, which are densely packed in values under 100 anyway.
543 * The Predicate<long> parameter must be a function that accepts a long and returns a bool. 502 * The Predicate<long> parameter must be a function that accepts a long and returns a bool.
544 * */ 503 * */
545 public long HalfIntervalMaximize(long start, Predicate<long> pred) 504 public long HalfIntervalMaximize (long start, Predicate<long> pred)
546 { 505 {
547 long prev = start, curr = start, biggest = 0; 506 long prev = start, curr = start, biggest = 0;
548 507
549 if(start < 0) 508 if (start < 0)
550 throw new IndexOutOfRangeException("Start value for HalfIntervalMaximize must be non-negative"); 509 throw new IndexOutOfRangeException ("Start value for HalfIntervalMaximize must be non-negative");
551 510
552 do 511 do {
553 { 512 if (pred (curr)) {
554 if(pred(curr)) 513 if (curr > biggest) {
555 {
556 if(curr > biggest)
557 {
558 biggest = curr; 514 biggest = curr;
559 } 515 }
560 prev = curr; 516 prev = curr;
561 if(curr == 0) 517 if (curr == 0) {
562 {
563 //Special case because 0 * 2 = 0 :) 518 //Special case because 0 * 2 = 0 :)
564 curr = 1; 519 curr = 1;
565 } 520 } else {
566 else
567 {
568 //Look deeper 521 //Look deeper
569 curr *= 2; 522 curr *= 2;
570 } 523 }
571 } 524 } else {
572 else
573 {
574 // We went too far, back off halfway 525 // We went too far, back off halfway
575 curr = (curr + prev) / 2; 526 curr = (curr + prev) / 2;
576 } 527 }
577 } 528 } while (curr - prev > 0);
578 while(curr - prev > 0);
579 529
580 return biggest; 530 return biggest;
581 } 531 }
582 532
583 public bool FileExistsTest(long num) 533 public bool FileExistsTest (long num)
584 { 534 {
585 FileInfo test = new FileInfo(m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + num + ".oar"); 535 FileInfo test = new FileInfo (m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + num + ".oar");
586 return test.Exists; 536 return test.Exists;
587 } 537 }
588 538
589 539
590 //Very slow, hence why we try the HalfIntervalMaximize first! 540 //Very slow, hence why we try the HalfIntervalMaximize first!
591 public FileInfo UniqueFileSearchLinear(long start) 541 public FileInfo UniqueFileSearchLinear (long start)
592 { 542 {
593 long l = start; 543 long l = start;
594 FileInfo retval = null; 544 FileInfo retval = null;
595 do 545 do {
596 { 546 retval = new FileInfo (m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + (l++) + ".oar");
597 retval = new FileInfo(m_dirName + Path.DirectorySeparatorChar + m_regionName + "_" + (l++) + ".oar"); 547 } while (retval.Exists);
598 }
599 while(retval.Exists);
600 548
601 return retval; 549 return retval;
602 } 550 }
603} 551 }
604 552
605} 553}
606 554