/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #region Header // FileSystemDatabase.cs // User: bongiojp #endregion Header using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using Slash = System.IO.Path; using System.Reflection; using System.Xml; using OpenMetaverse; using Nini.Config; using OpenSim.Framework; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Modules.World.Serialiser; using OpenSim.Region.Environment.Modules.World.Terrain; using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Physics.Manager; using log4net; namespace OpenSim.Region.Environment.Modules.ContentManagement { public class FileSystemDatabase : IContentDatabase { #region Static Fields public static float TimeToDownload = 0; public static float TimeToSave = 0; private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); #endregion Static Fields #region Fields private string m_repodir = null; private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>(); private Dictionary<UUID, IRegionSerialiser> m_serialiser = new Dictionary<UUID, IRegionSerialiser>(); #endregion Fields #region Constructors public FileSystemDatabase() { } #endregion Constructors #region Private Methods // called by postinitialise private void CreateDirectory() { string scenedir; if (!Directory.Exists(m_repodir)) Directory.CreateDirectory(m_repodir); foreach (UUID region in m_scenes.Keys) { scenedir = m_repodir + Slash.DirectorySeparatorChar + region + Slash.DirectorySeparatorChar; if (!Directory.Exists(scenedir)) Directory.CreateDirectory(scenedir); } } // called by postinitialise private void SetupSerialiser() { if (m_serialiser.Count == 0) foreach(UUID region in m_scenes.Keys) m_serialiser.Add(region, m_scenes[region].RequestModuleInterface<IRegionSerialiser>() ); } #endregion Private Methods #region Public Methods public int GetMostRecentRevision(UUID regionid) { return NumOfRegionRev(regionid); } public string GetRegionObjectHeightMap(UUID regionid) { String filename = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar + "heightmap.r32"; FileStream fs = new FileStream( filename, FileMode.Open); StreamReader sr = new StreamReader(fs); String result = sr.ReadToEnd(); sr.Close(); fs.Close(); return result; } public string GetRegionObjectHeightMap(UUID regionid, int revision) { String filename = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar + "heightmap.r32"; FileStream fs = new FileStream( filename, FileMode.Open); StreamReader sr = new StreamReader(fs); String result = sr.ReadToEnd(); sr.Close(); fs.Close(); return result; } public System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid, int revision) { System.Collections.ArrayList objectList = new System.Collections.ArrayList(); string filename = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar + + revision + Slash.DirectorySeparatorChar + "objects.xml"; XmlDocument doc = new XmlDocument(); XmlNode rootNode; //int primCount = 0; //SceneObjectGroup obj = null; if(File.Exists(filename)) { XmlTextReader reader = new XmlTextReader(filename); reader.WhitespaceHandling = WhitespaceHandling.None; doc.Load(reader); reader.Close(); rootNode = doc.FirstChild; foreach (XmlNode aPrimNode in rootNode.ChildNodes) { objectList.Add(aPrimNode.OuterXml); } return objectList; } return null; } public System.Collections.ArrayList GetRegionObjectXMLList(UUID regionid) { int revision = NumOfRegionRev(regionid); m_log.Info("[FSDB]: found revisions:" + revision); System.Collections.ArrayList xmlList = new System.Collections.ArrayList(); string filename = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar + + revision + Slash.DirectorySeparatorChar + "objects.xml"; XmlDocument doc = new XmlDocument(); XmlNode rootNode; m_log.Info("[FSDB]: Checking if " + filename + " exists."); if(File.Exists(filename)) { Stopwatch x = new Stopwatch(); x.Start(); XmlTextReader reader = new XmlTextReader(filename); reader.WhitespaceHandling = WhitespaceHandling.None; doc.Load(reader); reader.Close(); rootNode = doc.FirstChild; foreach (XmlNode aPrimNode in rootNode.ChildNodes) xmlList.Add(aPrimNode.OuterXml); x.Stop(); TimeToDownload += x.ElapsedMilliseconds; m_log.Info("[FileSystemDatabase] Time spent retrieving xml files so far: " + TimeToDownload); return xmlList; } return null; } public void Initialise(Scene scene, string dir) { lock(this) { if (m_repodir == null) m_repodir = dir; } lock(m_scenes) m_scenes.Add(scene.RegionInfo.RegionID, scene); } public System.Collections.Generic.SortedDictionary<string, string> ListOfRegionRevisions(UUID regionid) { SortedDictionary<string, string> revisionDict = new SortedDictionary<string,string>(); string scenedir = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar; string[] directories = Directory.GetDirectories(scenedir); FileStream fs = null; StreamReader sr = null; String logMessage = ""; String logLocation = ""; foreach(string revisionDir in directories) { try { logLocation = revisionDir + Slash.DirectorySeparatorChar + "log"; fs = new FileStream( logLocation, FileMode.Open); sr = new StreamReader(fs); logMessage = sr.ReadToEnd(); sr.Close(); fs.Close(); revisionDict.Add(revisionDir, logMessage); } catch (Exception) {} } return revisionDict; } public int NumOfRegionRev(UUID regionid) { string scenedir = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar; m_log.Info("[FSDB]: Reading scene dir: " + scenedir); string[] directories = Directory.GetDirectories(scenedir); return directories.Length; } // Run once and only once. public void PostInitialise() { SetupSerialiser(); m_log.Info("[FSDB]: Creating repository in " + m_repodir + "."); CreateDirectory(); } public void SaveRegion(UUID regionid, string regionName, string logMessage) { m_log.Info("[FSDB]: ..............................."); string scenedir = m_repodir + Slash.DirectorySeparatorChar + regionid + Slash.DirectorySeparatorChar; m_log.Info("[FSDB]: checking if scene directory exists: " + scenedir); if (!Directory.Exists(scenedir)) Directory.CreateDirectory(scenedir); int newRevisionNum = GetMostRecentRevision(regionid)+1; string revisiondir = scenedir + newRevisionNum + Slash.DirectorySeparatorChar; m_log.Info("[FSDB]: checking if revision directory exists: " + revisiondir); if (!Directory.Exists(revisiondir)) Directory.CreateDirectory(revisiondir); try { Stopwatch x = new Stopwatch(); x.Start(); if (m_scenes.ContainsKey(regionid)) { m_serialiser[regionid].SerialiseRegion(m_scenes[regionid], revisiondir); } x.Stop(); TimeToSave += x.ElapsedMilliseconds; m_log.Info("[FileSystemDatabase] Time spent serialising regions to files on disk for " + regionName + ": " + x.ElapsedMilliseconds); m_log.Info("[FileSystemDatabase] Time spent serialising regions to files on disk so far: " + TimeToSave); } catch (Exception e) { m_log.ErrorFormat("[FSDB]: Serialisation of region failed: " + e); return; } try { // Finish by writing log message. FileStream file = new FileStream(revisiondir + "log", FileMode.Create, FileAccess.ReadWrite); StreamWriter sw = new StreamWriter(file); sw.Write(logMessage); sw.Close(); } catch (Exception e) { m_log.ErrorFormat("[FSDB]: Failed trying to save log file " + e); return; } } #endregion Public Methods } }