aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
diff options
context:
space:
mode:
authorCharles Krinke2008-05-17 15:47:08 +0000
committerCharles Krinke2008-05-17 15:47:08 +0000
commitf6a4f8844f01fb756bbc26d65c252fc07ab8c2bf (patch)
treeda27e199a03ec4afd829a3ab9b06deab47cd02a3 /OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
parentwhile this doesn't fix the initial no pants issue in grid (which still baffle... (diff)
downloadopensim-SC_OLD-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.zip
opensim-SC_OLD-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.tar.gz
opensim-SC_OLD-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.tar.bz2
opensim-SC_OLD-f6a4f8844f01fb756bbc26d65c252fc07ab8c2bf.tar.xz
Thank you very much KMeisthax for DataSnapshot 1.1
to enhance search capability on OpenSim sims using external search engines such as Metaversink.com and others.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/DataSnapshot/DataSnapshotManager.cs451
1 files changed, 174 insertions, 277 deletions
diff --git a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
index af3e547..6fdedb4 100644
--- a/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
+++ b/OpenSim/Region/DataSnapshot/DataSnapshotManager.cs
@@ -37,49 +37,62 @@ using System.Xml;
37using libsecondlife; 37using libsecondlife;
38using log4net; 38using log4net;
39using Nini.Config; 39using Nini.Config;
40using OpenSim.Framework;
40using OpenSim.Framework.Communications; 41using OpenSim.Framework.Communications;
41using OpenSim.Region.DataSnapshot.Interfaces; 42using OpenSim.Region.DataSnapshot.Interfaces;
42using OpenSim.Region.Environment.Interfaces; 43using OpenSim.Region.Environment.Interfaces;
43using OpenSim.Region.Environment.Scenes; 44using OpenSim.Region.Environment.Scenes;
45using libsecondlife.Packets;
44 46
45namespace OpenSim.Region.DataSnapshot 47namespace OpenSim.Region.DataSnapshot
46{ 48{
47 public class DataSnapshotManager : IRegionModule 49 public class DataSnapshotManager : IRegionModule, IDataSnapshot
48 { 50 {
49 #region Class members 51 #region Class members
50 private List<Scene> m_scenes = new List<Scene>(); 52 //Information from config
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 private bool m_enabled = false; 53 private bool m_enabled = false;
53 private bool m_configLoaded = false; 54 private bool m_configLoaded = false;
54 internal object m_syncInit = new object(); 55 private List<String> m_disabledModules = new List<String>();
55 private DataRequestHandler m_requests = null;
56 private Dictionary<Scene, List<IDataSnapshotProvider>> m_dataproviders = new Dictionary<Scene, List<IDataSnapshotProvider>>();
57 private Dictionary<string, string> m_gridinfo = new Dictionary<string, string>(); 56 private Dictionary<string, string> m_gridinfo = new Dictionary<string, string>();
58 //private int m_oldestSnapshot = 0;
59 private int m_maxSnapshots = 500;
60 private int m_lastSnapshot = 0;
61 private string m_snapsDir = "DataSnapshot"; 57 private string m_snapsDir = "DataSnapshot";
58
59 //Lists of stuff we need
60 private List<Scene> m_scenes = new List<Scene>();
61 private List<IDataSnapshotProvider> m_dataproviders = new List<IDataSnapshotProvider>();
62
63 //Various internal objects
64 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
65 internal object m_syncInit = new object();
66
67 //DataServices and networking
62 private string m_dataServices = "noservices"; 68 private string m_dataServices = "noservices";
63 private string m_listener_port = "9000"; //TODO: Set default port over 9000 69 public string m_listener_port = "9000"; //TODO: Set default port over 9000
64 private string m_hostname = "127.0.0.1"; 70 public string m_hostname = "127.0.0.1";
71
72 //Update timers
65 private Timer m_periodic = null; 73 private Timer m_periodic = null;
66 private int m_period = 60; // in seconds 74 private int m_period = 20; // in seconds
67 private List<string> m_disabledModules = new List<string>(); 75 private int m_maxStales = 500;
76 private int m_stales = 0;
77 private Timer m_passedCheck = null;
78 private bool m_periodPassed = false;
79
80 //Program objects
81 private SnapshotStore m_snapStore = null;
82 private DataRequestHandler m_requests = null;
83
68 #endregion 84 #endregion
69 85
70 #region IRegionModule 86 #region IRegionModule
87
71 public void Close() 88 public void Close()
72 { 89 {
73 90 m_log.Info("[DATASNAPSHOT]: Close called");
74 } 91 }
75 92
76 public void Initialise(Scene scene, IConfigSource config) 93 public void Initialise(Scene scene, IConfigSource config)
77 { 94 {
78 if (!m_scenes.Contains(scene)) 95 if (!m_configLoaded) {
79 m_scenes.Add(scene);
80
81 if (!m_configLoaded)
82 {
83 m_configLoaded = true; 96 m_configLoaded = true;
84 m_log.Info("[DATASNAPSHOT]: Loading configuration"); 97 m_log.Info("[DATASNAPSHOT]: Loading configuration");
85 //Read from the config for options 98 //Read from the config for options
@@ -99,49 +112,59 @@ namespace OpenSim.Region.DataSnapshot
99 //Non gridmode stuff 112 //Non gridmode stuff
100 } 113 }
101 114
102 m_gridinfo.Add("Name", config.Configs["DataSnapshot"].GetString("gridname", "harbl")); 115 m_gridinfo.Add("Name", config.Configs["DataSnapshot"].GetString("gridname", "harbl"));
103 m_maxSnapshots = config.Configs["DataSnapshot"].GetInt("max_snapshots", m_maxSnapshots); 116 m_period = config.Configs["DataSnapshot"].GetInt("default_snapshot_period", m_period);
104 m_period = config.Configs["DataSnapshot"].GetInt("default_snapshot_period", m_period); 117 m_maxStales = config.Configs["DataSnapshot"].GetInt("max_changes_before_update", m_maxStales);
105 m_snapsDir = config.Configs["DataSnapshot"].GetString("snapshot_cache_directory", m_snapsDir); 118 m_snapsDir = config.Configs["DataSnapshot"].GetString("snapshot_cache_directory", m_snapsDir);
106 m_dataServices = config.Configs["DataSnapshot"].GetString("data_services", m_dataServices); 119 m_dataServices = config.Configs["DataSnapshot"].GetString("data_services", m_dataServices);
107 m_listener_port = config.Configs["Network"].GetString("http_listener_port", m_listener_port); 120 m_listener_port = config.Configs["Network"].GetString("http_listener_port", m_listener_port);
108 //BUG: Naming a search data module "DESUDESUDESU" will cause it to not get loaded by default. 121
109 //RESOLUTION: Wontfix, there are no Suiseiseki-loving developers 122 String[] annoying_string_array = config.Configs["DataSnapshot"].GetString("disable_modules", "").Split(".".ToCharArray());
110 String[] annoying_string_array = config.Configs["DataSnapshot"].GetString("disable_modules", "DESUDESUDESU").Split(".".ToCharArray()); 123 foreach (String bloody_wanker in annoying_string_array) {
111 foreach (String bloody_wanker in annoying_string_array) 124 m_disabledModules.Add(bloody_wanker);
112 { 125 }
113 m_disabledModules.Add(bloody_wanker); 126 } catch (Exception) {
114 }
115 }
116 catch (Exception)
117 {
118 m_log.Info("[DATASNAPSHOT]: Could not load configuration. DataSnapshot will be disabled."); 127 m_log.Info("[DATASNAPSHOT]: Could not load configuration. DataSnapshot will be disabled.");
119 m_enabled = false; 128 m_enabled = false;
120 return; 129 return;
121 } 130 }
122 } 131 }
123 } 132
124 if (Directory.Exists(m_snapsDir)) 133 m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
125 {
126 m_log.Info("[DATASNAPSHOT] DataSnapshot directory already exists.");
127 }
128 else
129 {
130 // Try to create the directory.
131 m_log.Info("[DATASNAPSHOT] Creating " + m_snapsDir + " directory.");
132 try
133 {
134 Directory.CreateDirectory(m_snapsDir);
135 }
136 catch (Exception)
137 {
138 m_log.Error("[DATASNAPSHOT] Failed to create " + m_snapsDir + " directory.");
139 }
140 } 134 }
141 135
142 if (m_enabled) 136 if (m_enabled)
143 { 137 {
144 m_log.Info("[DATASNAPSHOT]: Scene added to module."); 138 m_log.Info("[DATASNAPSHOT]: Scene added to module.");
139
140 m_snapStore.AddScene(scene);
141 m_scenes.Add(scene);
142
143 Assembly currentasm = Assembly.GetExecutingAssembly();
144
145 foreach (Type pluginType in currentasm.GetTypes())
146 {
147 if (pluginType.IsPublic)
148 {
149 if (!pluginType.IsAbstract)
150 {
151 if (pluginType.GetInterface("IDataSnapshotProvider") != null)
152 {
153 IDataSnapshotProvider module = (IDataSnapshotProvider)Activator.CreateInstance(pluginType);
154 module.Initialize(scene, this);
155 module.OnStale += MarkDataStale;
156
157 m_dataproviders.Add(module);
158 m_snapStore.AddProvider(module);
159
160 m_log.Info("[DATASNAPSHOT]: Added new data provider type: " + pluginType.Name);
161 }
162 }
163 }
164 }
165
166 //scene.OnRestart += OnSimRestart;
167 scene.EventManager.OnShutdown += delegate() { OnSimRestart(scene.RegionInfo); };
145 } 168 }
146 else 169 else
147 { 170 {
@@ -163,68 +186,35 @@ namespace OpenSim.Region.DataSnapshot
163 { 186 {
164 if (m_enabled) 187 if (m_enabled)
165 { 188 {
166 //Right now, only load ISearchData objects in the current assembly.
167 //Eventually allow it to load ISearchData objects from all assemblies.
168 Assembly currentasm = Assembly.GetExecutingAssembly();
169
170 //Stolen from ModuleLoader.cs
171 foreach (Type pluginType in currentasm.GetTypes())
172 {
173 if (pluginType.IsPublic)
174 {
175 if (!pluginType.IsAbstract)
176 {
177 if (pluginType.GetInterface("IDataSnapshotProvider") != null)
178 {
179 foreach (Scene scene in m_scenes)
180 {
181 IDataSnapshotProvider module = (IDataSnapshotProvider)Activator.CreateInstance(pluginType);
182 module.Initialize(scene, this);
183 //module.PrepareData();
184 List<IDataSnapshotProvider> providerlist = null;
185 m_dataproviders.TryGetValue(scene, out providerlist);
186 if (providerlist == null)
187 {
188 providerlist = new List<IDataSnapshotProvider>();
189 m_dataproviders.Add(scene, providerlist);
190 }
191 providerlist.Add(module);
192
193 }
194 m_log.Info("[DATASNAPSHOT]: Added new data provider type: " + pluginType.Name);
195 }
196 }
197 }
198 }
199
200 //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer 189 //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
201 m_requests = new DataRequestHandler(m_scenes[0], this); 190 m_requests = new DataRequestHandler(m_scenes[0], this);
202 191
203 //Create timer 192 //Create update timer
204 m_periodic = new Timer(); 193 m_periodic = new Timer();
205 m_periodic.Interval = m_period * 1000; 194 m_periodic.Interval = m_period * 1000;
206 m_periodic.Elapsed += SnapshotTimerCallback; 195 m_periodic.Elapsed += SnapshotTimerCallback;
207 m_periodic.Enabled = true; 196
197 //Create update eligibility timer
198 m_passedCheck = new Timer();
199 m_passedCheck.Interval = m_period * 1000;
200 m_passedCheck.Elapsed += UpdateEligibilityCallback;
201 m_passedCheck.Start();
208 202
209 m_hostname = m_scenes[0].RegionInfo.ExternalHostName; 203 m_hostname = m_scenes[0].RegionInfo.ExternalHostName;
210 204
211 MakeNewSnapshot(); //Make the initial snapshot 205 //m_snapStore = new SnapshotStore(m_snapsDir, m_dataproviders, m_gridinfo, m_listener_port, m_hostname);
206 MakeEverythingStale();
212 207
213 if (m_dataServices != "noservices") 208 if (m_dataServices != "noservices")
214 NotifyDataServices(m_dataServices); 209 NotifyDataServices(m_dataServices);
215 } 210 }
216 } 211 }
212
217 #endregion 213 #endregion
218 214
219 #region Associated helper functions 215 #region Associated helper functions
220 216
221 string DataFileName(Scene scene) 217 public Scene SceneForName(string name)
222 {
223 return Path.Combine(m_snapsDir, Path.ChangeExtension(scene.RegionInfo.RegionName, "xml"));
224 //return (m_snapsDir + Path.DirectorySeparatorChar + scene.RegionInfo.RegionName + ".xml");
225 }
226
227 Scene SceneForName(string name)
228 { 218 {
229 foreach (Scene scene in m_scenes) 219 foreach (Scene scene in m_scenes)
230 if (scene.RegionInfo.RegionName == name) 220 if (scene.RegionInfo.RegionName == name)
@@ -233,168 +223,19 @@ namespace OpenSim.Region.DataSnapshot
233 return null; 223 return null;
234 } 224 }
235 225
236 #endregion 226 public Scene SceneForUUID(LLUUID id)
237
238 #region [Private] XML snapshot generator
239
240 private XmlDocument Snapshot(Scene scene)
241 {
242 XmlDocument basedoc = new XmlDocument();
243 XmlNode regionElement = MakeRegionNode(scene, basedoc);
244
245 regionElement.AppendChild(GetGridSnapshotData(basedoc));
246 XmlNode regionData = basedoc.CreateNode(XmlNodeType.Element, "data", "");
247
248 foreach (KeyValuePair<Scene, List<IDataSnapshotProvider>> dataprovider in m_dataproviders)
249 {
250 if (dataprovider.Key == scene)
251 {
252 foreach (IDataSnapshotProvider provider in dataprovider.Value)
253 {
254 XmlNode data = provider.RequestSnapshotData(basedoc);
255 regionData.AppendChild(data);
256 }
257 }
258 }
259
260 regionElement.AppendChild(regionData);
261
262 basedoc.AppendChild(regionElement);
263
264 return basedoc;
265 }
266
267 private XmlNode MakeRegionNode(Scene scene, XmlDocument basedoc)
268 {
269 XmlNode docElement = basedoc.CreateNode(XmlNodeType.Element, "region", "");
270
271 XmlAttribute attr = basedoc.CreateAttribute("category");
272 attr.Value = GetRegionCategory(scene);
273 docElement.Attributes.Append(attr);
274
275 attr = basedoc.CreateAttribute("entities");
276 attr.Value = scene.Entities.Count.ToString();
277 docElement.Attributes.Append(attr);
278
279 //attr = basedoc.CreateAttribute("parcels");
280 //attr.Value = scene.LandManager.landList.Count.ToString();
281 //docElement.Attributes.Append(attr);
282
283
284 XmlNode infoblock = basedoc.CreateNode(XmlNodeType.Element, "info", "");
285
286 XmlNode infopiece = basedoc.CreateNode(XmlNodeType.Element, "uuid", "");
287 infopiece.InnerText = scene.RegionInfo.RegionID.ToString();
288 infoblock.AppendChild(infopiece);
289
290 infopiece = basedoc.CreateNode(XmlNodeType.Element, "url", "");
291 infopiece.InnerText = "http://" + m_hostname + ":" + m_listener_port;
292 infoblock.AppendChild(infopiece);
293
294 infopiece = basedoc.CreateNode(XmlNodeType.Element, "name", "");
295 infopiece.InnerText = scene.RegionInfo.RegionName;
296 infoblock.AppendChild(infopiece);
297
298 docElement.AppendChild(infoblock);
299
300 return docElement;
301 }
302
303 private XmlNode GetGridSnapshotData(XmlDocument factory)
304 {
305 XmlNode griddata = factory.CreateNode(XmlNodeType.Element, "grid", "");
306
307 foreach (KeyValuePair<String, String> GridData in m_gridinfo)
308 {
309 //TODO: make it lowercase tag names for diva
310 XmlNode childnode = factory.CreateNode(XmlNodeType.Element, GridData.Key, "");
311 childnode.InnerText = GridData.Value;
312 griddata.AppendChild(childnode);
313 }
314
315 return griddata;
316 }
317
318 private String GetRegionCategory(Scene scene)
319 { 227 {
228 foreach (Scene scene in m_scenes)
229 if (scene.RegionInfo.RegionID == id)
230 return scene;
320 231
321 //Boolean choice between: 232 return null;
322 // "PG" - Mormontown
323 // "Mature" - Sodom and Gomorrah
324 // (Depreciated) "Patriotic Nigra Testing Sandbox" - Abandon Hope All Ye Who Enter Here
325 if ((scene.RegionInfo.EstateSettings.simAccess & Simulator.SimAccess.Mature) == Simulator.SimAccess.Mature)
326 {
327 return "Mature";
328 }
329 else if ((scene.RegionInfo.EstateSettings.simAccess & Simulator.SimAccess.PG) == Simulator.SimAccess.PG)
330 {
331 return "PG";
332 }
333 else
334 {
335 return "Unknown";
336 }
337 } 233 }
338 234
339 /* Code's closed due to AIDS, See EstateSnapshot.cs for CURE
340 private XmlNode GetEstateSnapshotData(Scene scene, XmlDocument factory)
341 {
342 //Estate data section - contains who owns a set of sims and the name of the set.
343 //In Opensim all the estate names are the same as the Master Avatar (owner of the sim)
344 XmlNode estatedata = factory.CreateNode(XmlNodeType.Element, "estate", "");
345
346 LLUUID ownerid = scene.RegionInfo.MasterAvatarAssignedUUID;
347 String firstname = scene.RegionInfo.MasterAvatarFirstName;
348 String lastname = scene.RegionInfo.MasterAvatarLastName;
349 String hostname = scene.RegionInfo.ExternalHostName;
350
351 XmlNode user = factory.CreateNode(XmlNodeType.Element, "owner", "");
352
353 XmlNode username = factory.CreateNode(XmlNodeType.Element, "name", "");
354 username.InnerText = firstname + " " + lastname;
355 user.AppendChild(username);
356
357 XmlNode useruuid = factory.CreateNode(XmlNodeType.Element, "uuid", "");
358 useruuid.InnerText = ownerid.ToString();
359 user.AppendChild(useruuid);
360
361 estatedata.AppendChild(user);
362
363 return estatedata;
364 } */
365
366 #endregion 235 #endregion
367 236
368 #region [Public] Snapshot storage functions 237 #region [Public] Snapshot storage functions
369 238
370 public void MakeNewSnapshot()
371 {
372 foreach (Scene scene in m_scenes)
373 {
374 XmlDocument snapshot = Snapshot(scene);
375
376 string path = DataFileName(scene);
377
378 try
379 {
380 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
381 {
382 snapXWriter.Formatting = Formatting.Indented;
383 snapXWriter.WriteStartDocument();
384 snapshot.WriteTo(snapXWriter);
385 snapXWriter.WriteEndDocument();
386
387 m_lastSnapshot++;
388 }
389 }
390 catch (Exception e)
391 {
392 m_log.Warn("[DATASNAPSHOT]: Caught unknown exception while trying to save snapshot: " + path + "\n" + e.ToString());
393 }
394 m_log.Info("[DATASNAPSHOT]: Made external data snapshot " + path);
395 }
396 }
397
398 /** 239 /**
399 * Reply to the http request 240 * Reply to the http request
400 */ 241 */
@@ -410,30 +251,16 @@ namespace OpenSim.Region.DataSnapshot
410 { 251 {
411 foreach (Scene scene in m_scenes) 252 foreach (Scene scene in m_scenes)
412 { 253 {
413 string path = DataFileName(scene); 254 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
414 XmlDocument regionSnap = new XmlDocument();
415 regionSnap.PreserveWhitespace = true;
416
417 regionSnap.Load(path);
418 XmlNode nodeOrig = regionSnap["region"];
419 XmlNode nodeDest = requestedSnap.ImportNode(nodeOrig, true);
420 //requestedSnap.AppendChild(nodeDest);
421
422 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
423 regiondata.AppendChild(nodeDest);
424 } 255 }
425 } 256 }
426 else 257 else
427 { 258 {
428 Scene scene = SceneForName(regionName); 259 Scene scene = SceneForName(regionName);
429 requestedSnap.Load(DataFileName(scene)); 260 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
430 } 261 }
431 // requestedSnap.InsertBefore(requestedSnap.CreateXmlDeclaration("1.0", null, null),
432// requestedSnap.DocumentElement);
433 requestedSnap.AppendChild(regiondata); 262 requestedSnap.AppendChild(regiondata);
434 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n")); 263 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
435
436
437 } 264 }
438 catch (XmlException e) 265 catch (XmlException e)
439 { 266 {
@@ -469,16 +296,6 @@ namespace OpenSim.Region.DataSnapshot
469 296
470 #endregion 297 #endregion
471 298
472 #region Event callbacks
473
474 private void SnapshotTimerCallback(object timer, ElapsedEventArgs args)
475 {
476 MakeNewSnapshot();
477 //Add extra calls here
478 }
479
480 #endregion
481
482 #region External data services 299 #region External data services
483 private void NotifyDataServices(string servicesStr) 300 private void NotifyDataServices(string servicesStr)
484 { 301 {
@@ -524,5 +341,85 @@ namespace OpenSim.Region.DataSnapshot
524 341
525 } 342 }
526 #endregion 343 #endregion
344
345 #region Latency-based update functions
346
347 public void MarkDataStale(IDataSnapshotProvider provider)
348 {
349 //Behavior here: Wait m_period seconds, then update if there has not been a request in m_period seconds
350 //or m_maxStales has been exceeded
351 m_stales++;
352
353 if ((m_stales >= m_maxStales) && m_periodPassed)
354 SnapshotTimerCallback(m_periodic, null);
355 else if (m_periodic.Enabled == false)
356 m_periodic.Start();
357 else
358 {
359 m_periodic.Stop();
360 m_periodic.Start();
361 }
362 }
363
364 private void SnapshotTimerCallback(object timer, ElapsedEventArgs args)
365 {
366 m_log.Debug("[DATASNAPSHOT]: Marking scenes for snapshot updates.");
367
368 //Finally generate those snapshot updates
369 MakeEverythingStale();
370
371 //Stop the update delay timer
372 m_periodic.Stop();
373
374 //Reset the eligibility flag and timer
375 m_periodPassed = false;
376 m_passedCheck.Stop();
377 m_passedCheck.Start();
378 }
379
380 private void UpdateEligibilityCallback(object timer, ElapsedEventArgs args)
381 {
382 //Set eligibility, so we can start making updates
383 m_periodPassed = true;
384 }
385
386 public void MakeEverythingStale()
387 {
388 m_log.Debug("[DATASNAPSHOT]: Marking all scenes as stale.");
389 foreach (Scene scene in m_scenes)
390 {
391 m_snapStore.ForceSceneStale(scene);
392 }
393 }
394
395 #endregion
396
397 public void OnSimRestart(RegionInfo thisRegion)
398 {
399 m_log.Info("[DATASNAPSHOT]: Region " + thisRegion.RegionName + " is restarting, removing from indexing");
400 Scene restartedScene = SceneForUUID(thisRegion.RegionID);
401
402 m_scenes.Remove(restartedScene);
403 m_snapStore.RemoveScene(restartedScene);
404
405 //Getting around the fact that we can't remove objects from a collection we are enumerating over
406 List<IDataSnapshotProvider> providersToRemove = new List<IDataSnapshotProvider>();
407
408 foreach (IDataSnapshotProvider provider in m_dataproviders)
409 {
410 if (provider.GetParentScene == restartedScene)
411 {
412 providersToRemove.Add(provider);
413 }
414 }
415
416 foreach (IDataSnapshotProvider provider in providersToRemove)
417 {
418 m_dataproviders.Remove(provider);
419 m_snapStore.RemoveProvider(provider);
420 }
421
422 m_snapStore.RemoveScene(restartedScene);
423 }
527 } 424 }
528} 425}