/// <summary> /// Searches through the files in the archive for the control file, and reads it. /// We must read the control file first, in order to know which regions are available. /// </summary> /// <remarks> /// In most cases the control file *is* first, since that's how we create archives. However, /// it's possible that someone rewrote the archive externally so we can't rely on this fact. /// </remarks> /// <param name="archive"></param> /// <param name="dearchivedScenes"></param> private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes) { archive = new TarArchiveReader(m_loadStream); dearchivedScenes = new DearchiveScenesInfo(); string filePath; byte[] data; TarArchiveReader.TarEntryType entryType; bool firstFile = true; while ((data = archive.ReadEntry(out filePath, out entryType)) != null) { if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) continue; if (filePath == ArchiveConstants.CONTROL_FILE_PATH) { LoadControlFile(filePath, data, dearchivedScenes); // Find which scenes are available in the simulator ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup(); SceneManager.Instance.ForEachScene(delegate(Scene scene2) { simulatorScenes.AddScene(scene2); }); simulatorScenes.CalcSceneLocations(); dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes); // If the control file wasn't the first file then reset the read pointer if (!firstFile) { m_log.Warn("Control file wasn't the first file in the archive"); if (m_loadStream.CanSeek) { m_loadStream.Seek(0, SeekOrigin.Begin); } else if (m_loadPath != null) { archive.Close(); archive = null; m_loadStream.Close(); m_loadStream = null; m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress); archive = new TarArchiveReader(m_loadStream); } else { // There isn't currently a scenario where this happens, but it's best to add a check just in case throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking"); } } return; } firstFile = false; } throw new Exception("Control file not found"); }
/// <summary> /// Writes the list of regions included in a multi-region OAR. /// </summary> private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw) { xtw.WriteStartElement("regions"); // Write the regions in order: rows from South to North, then regions from West to East. // The list of regions can have "holes"; we write empty elements in their position. for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y) { SortedDictionary <uint, Scene> row; if (scenesGroup.Regions.TryGetValue(y, out row)) { xtw.WriteStartElement("row"); for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x) { Scene scene; if (row.TryGetValue(x, out scene)) { xtw.WriteStartElement("region"); xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString()); xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID)); WriteRegionInfo(scene, xtw); xtw.WriteEndElement(); } else { // Write a placeholder for a missing region xtw.WriteElementString("region", ""); } } xtw.WriteEndElement(); } else { // Write a placeholder for a missing row xtw.WriteElementString("row", ""); } } xtw.WriteEndElement(); // "regions" }
/// <summary> /// Sets all the scenes present in the simulator. /// </summary> /// <remarks> /// This method matches regions in the archive to scenes in the simulator according to /// their relative position. We only load regions if there's an existing Scene in the /// grid location where the region should be loaded. /// </remarks> /// <param name="rootScene">The scene where the Load OAR operation was run</param> /// <param name="simulatorScenes">All the scenes in the simulator</param> public void SetSimulatorScenes(Scene rootScene, ArchiveScenesGroup simulatorScenes) { foreach (RegionInfo archivedRegion in m_directory2region.Values) { Point location = new Point((int)rootScene.RegionInfo.RegionLocX, (int)rootScene.RegionInfo.RegionLocY); location.Offset(archivedRegion.Location); Scene scene; if (simulatorScenes.TryGetScene(location, out scene)) { archivedRegion.Scene = scene; m_newId2region[scene.RegionInfo.RegionID] = archivedRegion; } else { m_log.WarnFormat("[ARCHIVER]: Not loading archived region {0} because there's no existing region at location {1},{2}", archivedRegion.Directory, location.X, location.Y); } } }
/// <summary> /// Create the control file. /// </summary> /// <returns></returns> public string CreateControlFile(ArchiveScenesGroup scenesGroup) { int majorVersion; int minorVersion; if (MultiRegionFormat) { majorVersion = MAX_MAJOR_VERSION; minorVersion = 0; } else { // To support older versions of OpenSim, we continue to create single-region OARs // using the old file format. In the future this format will be discontinued. majorVersion = 0; minorVersion = 8; } // // if (m_options.ContainsKey("version")) // { // string[] parts = m_options["version"].ToString().Split('.'); // if (parts.Length >= 1) // { // majorVersion = Int32.Parse(parts[0]); // // if (parts.Length >= 2) // minorVersion = Int32.Parse(parts[1]); // } // } // // if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION) // { // throw new Exception( // string.Format( // "OAR version number for save must be between {0} and {1}", // MIN_MAJOR_VERSION, MAX_MAJOR_VERSION)); // } // else if (majorVersion == MAX_MAJOR_VERSION) // { // // Force 1.0 // minorVersion = 0; // } // else if (majorVersion == MIN_MAJOR_VERSION) // { // // Force 0.4 // minorVersion = 4; // } m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion); if (majorVersion == 1) { m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim versions prior to 0.7.4. Do not use the --all option if you want to produce a compatible OAR"); } String s; using (StringWriter sw = new StringWriter()) { using (XmlTextWriter xtw = new XmlTextWriter(sw)) { xtw.Formatting = Formatting.Indented; xtw.WriteStartDocument(); xtw.WriteStartElement("archive"); xtw.WriteAttributeString("major_version", majorVersion.ToString()); xtw.WriteAttributeString("minor_version", minorVersion.ToString()); xtw.WriteStartElement("creation_info"); DateTime now = DateTime.UtcNow; TimeSpan t = now - new DateTime(1970, 1, 1); xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); if (!MultiRegionFormat) { xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString()); } xtw.WriteEndElement(); xtw.WriteElementString("assets_included", SaveAssets.ToString()); if (MultiRegionFormat) { WriteRegionsManifest(scenesGroup, xtw); } else { xtw.WriteStartElement("region_info"); WriteRegionInfo(m_rootScene, xtw); xtw.WriteEndElement(); } xtw.WriteEndElement(); xtw.Flush(); } s = sw.ToString(); } return(s); }
/// <summary> /// Archive the region requested. /// </summary> /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> public void ArchiveRegion(Dictionary <string, object> options) { m_options = options; if (options.ContainsKey("all") && (bool)options["all"]) { MultiRegionFormat = true; } if (options.ContainsKey("noassets") && (bool)options["noassets"]) { SaveAssets = false; } if (options.TryGetValue("checkPermissions", out Object temp)) { FilterContent = (string)temp; } // Find the regions to archive ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); if (MultiRegionFormat) { m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count); SceneManager.Instance.ForEachScene(delegate(Scene scene) { scenesGroup.AddScene(scene); }); } else { scenesGroup.AddScene(m_rootScene); } scenesGroup.CalcSceneLocations(); m_archiveWriter = new TarArchiveWriter(m_saveStream); try { // Write out control file. It should be first so that it will be found ASAP when loading the file. m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup)); m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); // Archive the regions Dictionary <UUID, sbyte> assetUuids = new Dictionary <UUID, sbyte>(); HashSet <UUID> failedIDs = new HashSet <UUID>(); HashSet <UUID> uncertainAssetsUUIDs = new HashSet <UUID>(); scenesGroup.ForEachScene(delegate(Scene scene) { string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : ""; ArchiveOneRegion(scene, regionDir, assetUuids, failedIDs, uncertainAssetsUUIDs); }); // Archive the assets if (SaveAssets) { m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count); AssetsRequest ar = new AssetsRequest( new AssetsArchiver(m_archiveWriter), assetUuids, failedIDs.Count, m_rootScene.AssetService, m_rootScene.UserAccountService, m_rootScene.RegionInfo.ScopeID, options, null); ar.Execute(); assetUuids = null; } else { m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); // CloseArchive(string.Empty); } CloseArchive(string.Empty); } catch (Exception e) { CloseArchive(e.Message); throw; } GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.Default; }
/// <summary> /// Writes the list of regions included in a multi-region OAR. /// </summary> private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw) { xtw.WriteStartElement("regions"); // Write the regions in order: rows from South to North, then regions from West to East. // The list of regions can have "holes"; we write empty elements in their position. for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y) { SortedDictionary<uint, Scene> row; if (scenesGroup.Regions.TryGetValue(y, out row)) { xtw.WriteStartElement("row"); for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x) { Scene scene; if (row.TryGetValue(x, out scene)) { xtw.WriteStartElement("region"); xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString()); xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID)); WriteRegionInfo(scene, xtw); xtw.WriteEndElement(); } else { // Write a placeholder for a missing region xtw.WriteElementString("region", ""); } } xtw.WriteEndElement(); } else { // Write a placeholder for a missing row xtw.WriteElementString("row", ""); } } xtw.WriteEndElement(); // "regions" }
/// <summary> /// Create the control file. /// </summary> /// <returns></returns> public string CreateControlFile(ArchiveScenesGroup scenesGroup) { int majorVersion; int minorVersion; if (MultiRegionFormat) { majorVersion = MAX_MAJOR_VERSION; minorVersion = 0; } else { // To support older versions of OpenSim, we continue to create single-region OARs // using the old file format. In the future this format will be discontinued. majorVersion = 0; minorVersion = 8; } // // if (m_options.ContainsKey("version")) // { // string[] parts = m_options["version"].ToString().Split('.'); // if (parts.Length >= 1) // { // majorVersion = Int32.Parse(parts[0]); // // if (parts.Length >= 2) // minorVersion = Int32.Parse(parts[1]); // } // } // // if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION) // { // throw new Exception( // string.Format( // "OAR version number for save must be between {0} and {1}", // MIN_MAJOR_VERSION, MAX_MAJOR_VERSION)); // } // else if (majorVersion == MAX_MAJOR_VERSION) // { // // Force 1.0 // minorVersion = 0; // } // else if (majorVersion == MIN_MAJOR_VERSION) // { // // Force 0.4 // minorVersion = 4; // } m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion); if (majorVersion == 1) { m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim versions prior to 0.7.4. Do not use the --all option if you want to produce a compatible OAR"); } String s; using (StringWriter sw = new StringWriter()) { using (XmlTextWriter xtw = new XmlTextWriter(sw)) { xtw.Formatting = Formatting.Indented; xtw.WriteStartDocument(); xtw.WriteStartElement("archive"); xtw.WriteAttributeString("major_version", majorVersion.ToString()); xtw.WriteAttributeString("minor_version", minorVersion.ToString()); xtw.WriteStartElement("creation_info"); DateTime now = DateTime.UtcNow; TimeSpan t = now - new DateTime(1970, 1, 1); xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); if (!MultiRegionFormat) xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString()); xtw.WriteEndElement(); xtw.WriteElementString("assets_included", SaveAssets.ToString()); if (MultiRegionFormat) { WriteRegionsManifest(scenesGroup, xtw); } else { xtw.WriteStartElement("region_info"); WriteRegionInfo(m_rootScene, xtw); xtw.WriteEndElement(); } xtw.WriteEndElement(); xtw.Flush(); } s = sw.ToString(); } return s; }
/// <summary> /// Archive the region requested. /// </summary> /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> public void ArchiveRegion(Dictionary<string, object> options) { m_options = options; if (options.ContainsKey("all") && (bool)options["all"]) MultiRegionFormat = true; if (options.ContainsKey("noassets") && (bool)options["noassets"]) SaveAssets = false; Object temp; if (options.TryGetValue("checkPermissions", out temp)) FilterContent = (string)temp; // Find the regions to archive ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); if (MultiRegionFormat) { m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count); SceneManager.Instance.ForEachScene(delegate(Scene scene) { scenesGroup.AddScene(scene); }); } else { scenesGroup.AddScene(m_rootScene); } scenesGroup.CalcSceneLocations(); m_archiveWriter = new TarArchiveWriter(m_saveStream); try { // Write out control file. It should be first so that it will be found ASAP when loading the file. m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup)); m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); // Archive the regions Dictionary<UUID, sbyte> assetUuids = new Dictionary<UUID, sbyte>(); scenesGroup.ForEachScene(delegate(Scene scene) { string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : ""; ArchiveOneRegion(scene, regionDir, assetUuids); }); // Archive the assets if (SaveAssets) { m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count); // Asynchronously request all the assets required to perform this archive operation AssetsRequest ar = new AssetsRequest( new AssetsArchiver(m_archiveWriter), assetUuids, m_rootScene.AssetService, m_rootScene.UserAccountService, m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); WorkManager.RunInThread(o => ar.Execute(), null, "Archive Assets Request"); // CloseArchive() will be called from ReceivedAllAssets() } else { m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); CloseArchive(string.Empty); } } catch (Exception e) { CloseArchive(e.Message); throw; } }
/// <summary> /// Archive the region requested. /// </summary> /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> public void ArchiveRegion(Dictionary <string, object> options) { m_options = options; if (options.ContainsKey("all") && (bool)options["all"]) { MultiRegionFormat = true; } if (options.ContainsKey("noassets") && (bool)options["noassets"]) { SaveAssets = false; } Object temp; if (options.TryGetValue("checkPermissions", out temp)) { CheckPermissions = (string)temp; } // Find the regions to archive ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); if (MultiRegionFormat) { m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count); SceneManager.Instance.ForEachScene(delegate(Scene scene) { scenesGroup.AddScene(scene); }); } else { scenesGroup.AddScene(m_rootScene); } scenesGroup.CalcSceneLocations(); m_archiveWriter = new TarArchiveWriter(m_saveStream); try { // Write out control file. It should be first so that it will be found ASAP when loading the file. m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup)); m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); // Archive the regions Dictionary <UUID, AssetType> assetUuids = new Dictionary <UUID, AssetType>(); scenesGroup.ForEachScene(delegate(Scene scene) { string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : ""; ArchiveOneRegion(scene, regionDir, assetUuids); }); // Archive the assets if (SaveAssets) { m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count); // Asynchronously request all the assets required to perform this archive operation AssetsRequest ar = new AssetsRequest( new AssetsArchiver(m_archiveWriter), assetUuids, m_rootScene.AssetService, m_rootScene.UserAccountService, m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); Util.FireAndForget(o => ar.Execute()); // CloseArchive() will be called from ReceivedAllAssets() } else { m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); CloseArchive(string.Empty); } } catch (Exception e) { CloseArchive(e.Message); throw; } }