diff options
author | Oren Hurvitz | 2012-07-24 19:48:08 +0300 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2012-09-14 20:25:03 +0100 |
commit | ce468215d576cc301a261d85bee9baa68a246ce6 (patch) | |
tree | ad2c6d7e3156bf8dab596f2772cc712d4f96c698 /OpenSim/Region/CoreModules/World | |
parent | Don't store the unnecessary VERSIONMIN. VERSIONMAX, METHOD or UserID (present... (diff) | |
download | opensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.zip opensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.tar.gz opensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.tar.bz2 opensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.tar.xz |
Support multi-region OAR files
Merged ArchiveWriteRequestPreparation.cs and ArchiveWriteRequestExecution.cs. This simplifies the code, and it's faster to write each scene to the archive as it's found rather than all at once at the end.
Diffstat (limited to 'OpenSim/Region/CoreModules/World')
8 files changed, 1057 insertions, 395 deletions
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index 433166d..a6923ef 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | |||
@@ -43,6 +43,7 @@ using OpenSim.Region.Framework.Interfaces; | |||
43 | using OpenSim.Region.Framework.Scenes; | 43 | using OpenSim.Region.Framework.Scenes; |
44 | using OpenSim.Region.Framework.Scenes.Serialization; | 44 | using OpenSim.Region.Framework.Scenes.Serialization; |
45 | using OpenSim.Services.Interfaces; | 45 | using OpenSim.Services.Interfaces; |
46 | using System.Threading; | ||
46 | 47 | ||
47 | namespace OpenSim.Region.CoreModules.World.Archiver | 48 | namespace OpenSim.Region.CoreModules.World.Archiver |
48 | { | 49 | { |
@@ -52,7 +53,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
52 | public class ArchiveReadRequest | 53 | public class ArchiveReadRequest |
53 | { | 54 | { |
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 55 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
56 | |||
57 | /// <summary> | ||
58 | /// Contains data used while dearchiving a single scene. | ||
59 | /// </summary> | ||
60 | private class DearchiveContext | ||
61 | { | ||
62 | public Scene Scene { get; set; } | ||
63 | |||
64 | public List<string> SerialisedSceneObjects { get; set; } | ||
65 | |||
66 | public List<string> SerialisedParcels { get; set; } | ||
67 | |||
68 | public List<SceneObjectGroup> SceneObjects { get; set; } | ||
69 | |||
70 | public DearchiveContext(Scene scene) | ||
71 | { | ||
72 | Scene = scene; | ||
73 | SerialisedSceneObjects = new List<string>(); | ||
74 | SerialisedParcels = new List<string>(); | ||
75 | SceneObjects = new List<SceneObjectGroup>(); | ||
76 | } | ||
77 | } | ||
55 | 78 | ||
79 | |||
56 | /// <summary> | 80 | /// <summary> |
57 | /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version | 81 | /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version |
58 | /// bumps here should be compatible. | 82 | /// bumps here should be compatible. |
@@ -62,9 +86,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
62 | /// <summary> | 86 | /// <summary> |
63 | /// Has the control file been loaded for this archive? | 87 | /// Has the control file been loaded for this archive? |
64 | /// </summary> | 88 | /// </summary> |
65 | public bool ControlFileLoaded { get; private set; } | 89 | public bool ControlFileLoaded { get; private set; } |
66 | 90 | ||
67 | protected Scene m_scene; | 91 | protected string m_loadPath; |
92 | protected Scene m_rootScene; | ||
68 | protected Stream m_loadStream; | 93 | protected Stream m_loadStream; |
69 | protected Guid m_requestId; | 94 | protected Guid m_requestId; |
70 | protected string m_errorMessage; | 95 | protected string m_errorMessage; |
@@ -91,7 +116,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
91 | { | 116 | { |
92 | if (m_UserMan == null) | 117 | if (m_UserMan == null) |
93 | { | 118 | { |
94 | m_UserMan = m_scene.RequestModuleInterface<IUserManagement>(); | 119 | m_UserMan = m_rootScene.RequestModuleInterface<IUserManagement>(); |
95 | } | 120 | } |
96 | return m_UserMan; | 121 | return m_UserMan; |
97 | } | 122 | } |
@@ -104,10 +129,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
104 | 129 | ||
105 | private IGroupsModule m_groupsModule; | 130 | private IGroupsModule m_groupsModule; |
106 | 131 | ||
132 | private IAssetService m_assetService = null; | ||
133 | |||
134 | |||
107 | public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) | 135 | public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) |
108 | { | 136 | { |
109 | m_scene = scene; | 137 | m_rootScene = scene; |
110 | 138 | ||
139 | m_loadPath = loadPath; | ||
111 | try | 140 | try |
112 | { | 141 | { |
113 | m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress); | 142 | m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress); |
@@ -128,12 +157,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
128 | // Zero can never be a valid user id | 157 | // Zero can never be a valid user id |
129 | m_validUserUuids[UUID.Zero] = false; | 158 | m_validUserUuids[UUID.Zero] = false; |
130 | 159 | ||
131 | m_groupsModule = m_scene.RequestModuleInterface<IGroupsModule>(); | 160 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); |
161 | m_assetService = m_rootScene.AssetService; | ||
132 | } | 162 | } |
133 | 163 | ||
134 | public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) | 164 | public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) |
135 | { | 165 | { |
136 | m_scene = scene; | 166 | m_rootScene = scene; |
167 | m_loadPath = null; | ||
137 | m_loadStream = loadStream; | 168 | m_loadStream = loadStream; |
138 | m_merge = merge; | 169 | m_merge = merge; |
139 | m_skipAssets = skipAssets; | 170 | m_skipAssets = skipAssets; |
@@ -142,7 +173,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
142 | // Zero can never be a valid user id | 173 | // Zero can never be a valid user id |
143 | m_validUserUuids[UUID.Zero] = false; | 174 | m_validUserUuids[UUID.Zero] = false; |
144 | 175 | ||
145 | m_groupsModule = m_scene.RequestModuleInterface<IGroupsModule>(); | 176 | m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>(); |
177 | m_assetService = m_rootScene.AssetService; | ||
146 | } | 178 | } |
147 | 179 | ||
148 | /// <summary> | 180 | /// <summary> |
@@ -150,25 +182,25 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
150 | /// </summary> | 182 | /// </summary> |
151 | public void DearchiveRegion() | 183 | public void DearchiveRegion() |
152 | { | 184 | { |
153 | // The same code can handle dearchiving 0.1 and 0.2 OpenSim Archive versions | ||
154 | DearchiveRegion0DotStar(); | ||
155 | } | ||
156 | |||
157 | private void DearchiveRegion0DotStar() | ||
158 | { | ||
159 | int successfulAssetRestores = 0; | 185 | int successfulAssetRestores = 0; |
160 | int failedAssetRestores = 0; | 186 | int failedAssetRestores = 0; |
161 | List<string> serialisedSceneObjects = new List<string>(); | ||
162 | List<string> serialisedParcels = new List<string>(); | ||
163 | string filePath = "NONE"; | ||
164 | 187 | ||
165 | TarArchiveReader archive = new TarArchiveReader(m_loadStream); | 188 | DearchiveScenesInfo dearchivedScenes; |
189 | |||
190 | // We dearchive all the scenes at once, because the files in the TAR archive might be mixed. | ||
191 | // Therefore, we have to keep track of the dearchive context of all the scenes. | ||
192 | Dictionary<UUID, DearchiveContext> sceneContexts = new Dictionary<UUID, DearchiveContext>(); | ||
193 | |||
194 | string fullPath = "NONE"; | ||
195 | TarArchiveReader archive = null; | ||
166 | byte[] data; | 196 | byte[] data; |
167 | TarArchiveReader.TarEntryType entryType; | 197 | TarArchiveReader.TarEntryType entryType; |
168 | 198 | ||
169 | try | 199 | try |
170 | { | 200 | { |
171 | while ((data = archive.ReadEntry(out filePath, out entryType)) != null) | 201 | FindAndLoadControlFile(out archive, out dearchivedScenes); |
202 | |||
203 | while ((data = archive.ReadEntry(out fullPath, out entryType)) != null) | ||
172 | { | 204 | { |
173 | //m_log.DebugFormat( | 205 | //m_log.DebugFormat( |
174 | // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length); | 206 | // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length); |
@@ -176,9 +208,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
176 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) | 208 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) |
177 | continue; | 209 | continue; |
178 | 210 | ||
211 | |||
212 | // Find the scene that this file belongs to | ||
213 | |||
214 | Scene scene; | ||
215 | string filePath; | ||
216 | if (!dearchivedScenes.GetRegionFromPath(fullPath, out scene, out filePath)) | ||
217 | continue; // this file belongs to a region that we're not loading | ||
218 | |||
219 | DearchiveContext sceneContext = null; | ||
220 | if (scene != null) | ||
221 | { | ||
222 | if (!sceneContexts.TryGetValue(scene.RegionInfo.RegionID, out sceneContext)) | ||
223 | { | ||
224 | sceneContext = new DearchiveContext(scene); | ||
225 | sceneContexts.Add(scene.RegionInfo.RegionID, sceneContext); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | |||
230 | // Process the file | ||
231 | |||
179 | if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) | 232 | if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) |
180 | { | 233 | { |
181 | serialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); | 234 | sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); |
182 | } | 235 | } |
183 | else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets) | 236 | else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets) |
184 | { | 237 | { |
@@ -192,19 +245,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
192 | } | 245 | } |
193 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) | 246 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) |
194 | { | 247 | { |
195 | LoadTerrain(filePath, data); | 248 | LoadTerrain(scene, filePath, data); |
196 | } | 249 | } |
197 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) | 250 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) |
198 | { | 251 | { |
199 | LoadRegionSettings(filePath, data); | 252 | LoadRegionSettings(scene, filePath, data, dearchivedScenes); |
200 | } | 253 | } |
201 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) | 254 | else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) |
202 | { | 255 | { |
203 | serialisedParcels.Add(Encoding.UTF8.GetString(data)); | 256 | sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); |
204 | } | 257 | } |
205 | else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) | 258 | else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) |
206 | { | 259 | { |
207 | LoadControlFile(filePath, data); | 260 | // Ignore, because we already read the control file |
208 | } | 261 | } |
209 | } | 262 | } |
210 | 263 | ||
@@ -212,15 +265,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
212 | } | 265 | } |
213 | catch (Exception e) | 266 | catch (Exception e) |
214 | { | 267 | { |
215 | m_log.ErrorFormat( | 268 | m_log.Error( |
216 | "[ARCHIVER]: Aborting load with error in archive file {0}. {1}", filePath, e); | 269 | String.Format("[ARCHIVER]: Aborting load with error in archive file {0} ", fullPath), e); |
217 | m_errorMessage += e.ToString(); | 270 | m_errorMessage += e.ToString(); |
218 | m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage); | 271 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage); |
219 | return; | 272 | return; |
220 | } | 273 | } |
221 | finally | 274 | finally |
222 | { | 275 | { |
223 | archive.Close(); | 276 | if (archive != null) |
277 | archive.Close(); | ||
224 | } | 278 | } |
225 | 279 | ||
226 | if (!m_skipAssets) | 280 | if (!m_skipAssets) |
@@ -234,32 +288,143 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
234 | } | 288 | } |
235 | } | 289 | } |
236 | 290 | ||
237 | if (!m_merge) | 291 | foreach (DearchiveContext sceneContext in sceneContexts.Values) |
238 | { | 292 | { |
239 | m_log.Info("[ARCHIVER]: Clearing all existing scene objects"); | 293 | m_log.InfoFormat("[ARCHIVER:] Loading region {0}", sceneContext.Scene.RegionInfo.RegionName); |
240 | m_scene.DeleteAllSceneObjects(); | 294 | |
295 | if (!m_merge) | ||
296 | { | ||
297 | m_log.Info("[ARCHIVER]: Clearing all existing scene objects"); | ||
298 | sceneContext.Scene.DeleteAllSceneObjects(); | ||
299 | } | ||
300 | |||
301 | try | ||
302 | { | ||
303 | LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels); | ||
304 | LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects); | ||
305 | |||
306 | // Inform any interested parties that the region has changed. We waited until now so that all | ||
307 | // of the region's objects will be loaded when we send this notification. | ||
308 | IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface<IEstateModule>(); | ||
309 | if (estateModule != null) | ||
310 | estateModule.TriggerRegionInfoChange(); | ||
311 | } | ||
312 | catch (Exception e) | ||
313 | { | ||
314 | m_log.Error("[ARCHIVER]: Error loading parcels or objects ", e); | ||
315 | m_errorMessage += e.ToString(); | ||
316 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage); | ||
317 | return; | ||
318 | } | ||
241 | } | 319 | } |
242 | 320 | ||
243 | LoadParcels(serialisedParcels); | 321 | // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so |
244 | LoadObjects(serialisedSceneObjects); | 322 | // that users can enter the scene. If we allow the scripts to start in the loop above |
323 | // then they significantly increase the time until the OAR finishes loading. | ||
324 | Util.FireAndForget(delegate(object o) | ||
325 | { | ||
326 | Thread.Sleep(15000); | ||
327 | m_log.Info("Starting scripts in scene objects"); | ||
328 | |||
329 | foreach (DearchiveContext sceneContext in sceneContexts.Values) | ||
330 | { | ||
331 | foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects) | ||
332 | { | ||
333 | sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart | ||
334 | sceneObject.ResumeScripts(); | ||
335 | } | ||
336 | |||
337 | sceneContext.SceneObjects.Clear(); | ||
338 | } | ||
339 | }); | ||
245 | 340 | ||
246 | m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); | 341 | m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); |
247 | 342 | ||
248 | m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage); | 343 | m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, dearchivedScenes.GetLoadedScenes(), m_errorMessage); |
344 | } | ||
345 | |||
346 | /// <summary> | ||
347 | /// Searches through the files in the archive for the control file, and reads it. | ||
348 | /// We must read the control file first, in order to know which regions are available. | ||
349 | /// </summary> | ||
350 | /// <remarks> | ||
351 | /// In most cases the control file *is* first, since that's how we create archives. However, | ||
352 | /// it's possible that someone rewrote the archive externally so we can't rely on this fact. | ||
353 | /// </remarks> | ||
354 | /// <param name="archive"></param> | ||
355 | /// <param name="dearchivedScenes"></param> | ||
356 | private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes) | ||
357 | { | ||
358 | archive = new TarArchiveReader(m_loadStream); | ||
359 | dearchivedScenes = new DearchiveScenesInfo(); | ||
360 | |||
361 | string filePath; | ||
362 | byte[] data; | ||
363 | TarArchiveReader.TarEntryType entryType; | ||
364 | bool firstFile = true; | ||
365 | |||
366 | while ((data = archive.ReadEntry(out filePath, out entryType)) != null) | ||
367 | { | ||
368 | if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) | ||
369 | continue; | ||
370 | |||
371 | if (filePath == ArchiveConstants.CONTROL_FILE_PATH) | ||
372 | { | ||
373 | LoadControlFile(filePath, data, dearchivedScenes); | ||
374 | |||
375 | // Find which scenes are available in the simulator | ||
376 | ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup(); | ||
377 | SceneManager.Instance.ForEachScene(delegate(Scene scene2) | ||
378 | { | ||
379 | simulatorScenes.AddScene(scene2); | ||
380 | }); | ||
381 | simulatorScenes.CalcSceneLocations(); | ||
382 | dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes); | ||
383 | |||
384 | // If the control file wasn't the first file then reset the read pointer | ||
385 | if (!firstFile) | ||
386 | { | ||
387 | m_log.Warn("Control file wasn't the first file in the archive"); | ||
388 | if (m_loadStream.CanSeek) | ||
389 | { | ||
390 | m_loadStream.Seek(0, SeekOrigin.Begin); | ||
391 | } | ||
392 | else if (m_loadPath != null) | ||
393 | { | ||
394 | archive.Close(); | ||
395 | archive = null; | ||
396 | m_loadStream.Close(); | ||
397 | m_loadStream = null; | ||
398 | m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress); | ||
399 | archive = new TarArchiveReader(m_loadStream); | ||
400 | } | ||
401 | else | ||
402 | { | ||
403 | // There isn't currently a scenario where this happens, but it's best to add a check just in case | ||
404 | throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking"); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | return; | ||
409 | } | ||
410 | |||
411 | firstFile = false; | ||
412 | } | ||
413 | |||
414 | throw new Exception("Control file not found"); | ||
249 | } | 415 | } |
250 | 416 | ||
251 | /// <summary> | 417 | /// <summary> |
252 | /// Load serialized scene objects. | 418 | /// Load serialized scene objects. |
253 | /// </summary> | 419 | /// </summary> |
254 | /// <param name="serialisedSceneObjects"></param> | 420 | protected void LoadObjects(Scene scene, List<string> serialisedSceneObjects, List<SceneObjectGroup> sceneObjects) |
255 | protected void LoadObjects(List<string> serialisedSceneObjects) | ||
256 | { | 421 | { |
257 | // Reload serialized prims | 422 | // Reload serialized prims |
258 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); | 423 | m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); |
259 | 424 | ||
260 | UUID oldTelehubUUID = m_scene.RegionInfo.RegionSettings.TelehubObject; | 425 | UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; |
261 | 426 | ||
262 | IRegionSerialiserModule serialiser = m_scene.RequestModuleInterface<IRegionSerialiserModule>(); | 427 | IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>(); |
263 | int sceneObjectsLoadedCount = 0; | 428 | int sceneObjectsLoadedCount = 0; |
264 | 429 | ||
265 | foreach (string serialisedSceneObject in serialisedSceneObjects) | 430 | foreach (string serialisedSceneObject in serialisedSceneObjects) |
@@ -280,7 +445,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
280 | 445 | ||
281 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); | 446 | SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); |
282 | 447 | ||
283 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID); | 448 | bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); |
284 | 449 | ||
285 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned | 450 | // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned |
286 | // on the same region server and multiple examples a single object archive to be imported | 451 | // on the same region server and multiple examples a single object archive to be imported |
@@ -290,8 +455,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
290 | if (isTelehub) | 455 | if (isTelehub) |
291 | { | 456 | { |
292 | // Change the Telehub Object to the new UUID | 457 | // Change the Telehub Object to the new UUID |
293 | m_scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID; | 458 | scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID; |
294 | m_scene.RegionInfo.RegionSettings.Save(); | 459 | scene.RegionInfo.RegionSettings.Save(); |
295 | oldTelehubUUID = UUID.Zero; | 460 | oldTelehubUUID = UUID.Zero; |
296 | } | 461 | } |
297 | 462 | ||
@@ -301,17 +466,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
301 | { | 466 | { |
302 | if (part.CreatorData == null || part.CreatorData == string.Empty) | 467 | if (part.CreatorData == null || part.CreatorData == string.Empty) |
303 | { | 468 | { |
304 | if (!ResolveUserUuid(part.CreatorID)) | 469 | if (!ResolveUserUuid(scene, part.CreatorID)) |
305 | part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 470 | part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; |
306 | } | 471 | } |
307 | if (UserManager != null) | 472 | if (UserManager != null) |
308 | UserManager.AddUser(part.CreatorID, part.CreatorData); | 473 | UserManager.AddUser(part.CreatorID, part.CreatorData); |
309 | 474 | ||
310 | if (!ResolveUserUuid(part.OwnerID)) | 475 | if (!ResolveUserUuid(scene, part.OwnerID)) |
311 | part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 476 | part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
312 | 477 | ||
313 | if (!ResolveUserUuid(part.LastOwnerID)) | 478 | if (!ResolveUserUuid(scene, part.LastOwnerID)) |
314 | part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 479 | part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
315 | 480 | ||
316 | if (!ResolveGroupUuid(part.GroupID)) | 481 | if (!ResolveGroupUuid(part.GroupID)) |
317 | part.GroupID = UUID.Zero; | 482 | part.GroupID = UUID.Zero; |
@@ -328,15 +493,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
328 | TaskInventoryDictionary inv = part.TaskInventory; | 493 | TaskInventoryDictionary inv = part.TaskInventory; |
329 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) | 494 | foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) |
330 | { | 495 | { |
331 | if (!ResolveUserUuid(kvp.Value.OwnerID)) | 496 | if (!ResolveUserUuid(scene, kvp.Value.OwnerID)) |
332 | { | 497 | { |
333 | kvp.Value.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 498 | kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; |
334 | } | 499 | } |
335 | 500 | ||
336 | if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty) | 501 | if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty) |
337 | { | 502 | { |
338 | if (!ResolveUserUuid(kvp.Value.CreatorID)) | 503 | if (!ResolveUserUuid(scene, kvp.Value.CreatorID)) |
339 | kvp.Value.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 504 | kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; |
340 | } | 505 | } |
341 | 506 | ||
342 | if (UserManager != null) | 507 | if (UserManager != null) |
@@ -348,10 +513,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
348 | } | 513 | } |
349 | } | 514 | } |
350 | 515 | ||
351 | if (m_scene.AddRestoredSceneObject(sceneObject, true, false)) | 516 | if (scene.AddRestoredSceneObject(sceneObject, true, false)) |
352 | { | 517 | { |
353 | sceneObjectsLoadedCount++; | 518 | sceneObjectsLoadedCount++; |
354 | sceneObject.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, 0); | 519 | sceneObject.CreateScriptInstances(0, false, scene.DefaultScriptEngine, 0); |
355 | sceneObject.ResumeScripts(); | 520 | sceneObject.ResumeScripts(); |
356 | } | 521 | } |
357 | } | 522 | } |
@@ -366,16 +531,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
366 | if (oldTelehubUUID != UUID.Zero) | 531 | if (oldTelehubUUID != UUID.Zero) |
367 | { | 532 | { |
368 | m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); | 533 | m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); |
369 | m_scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; | 534 | scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; |
370 | m_scene.RegionInfo.RegionSettings.ClearSpawnPoints(); | 535 | scene.RegionInfo.RegionSettings.ClearSpawnPoints(); |
371 | } | 536 | } |
372 | } | 537 | } |
373 | 538 | ||
374 | /// <summary> | 539 | /// <summary> |
375 | /// Load serialized parcels. | 540 | /// Load serialized parcels. |
376 | /// </summary> | 541 | /// </summary> |
542 | /// <param name="scene"></param> | ||
377 | /// <param name="serialisedParcels"></param> | 543 | /// <param name="serialisedParcels"></param> |
378 | protected void LoadParcels(List<string> serialisedParcels) | 544 | protected void LoadParcels(Scene scene, List<string> serialisedParcels) |
379 | { | 545 | { |
380 | // Reload serialized parcels | 546 | // Reload serialized parcels |
381 | m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count); | 547 | m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count); |
@@ -386,8 +552,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
386 | 552 | ||
387 | // Validate User and Group UUID's | 553 | // Validate User and Group UUID's |
388 | 554 | ||
389 | if (!ResolveUserUuid(parcel.OwnerID)) | 555 | if (!ResolveUserUuid(scene, parcel.OwnerID)) |
390 | parcel.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; | 556 | parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; |
391 | 557 | ||
392 | if (!ResolveGroupUuid(parcel.GroupID)) | 558 | if (!ResolveGroupUuid(parcel.GroupID)) |
393 | { | 559 | { |
@@ -398,7 +564,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
398 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); | 564 | List<LandAccessEntry> accessList = new List<LandAccessEntry>(); |
399 | foreach (LandAccessEntry entry in parcel.ParcelAccessList) | 565 | foreach (LandAccessEntry entry in parcel.ParcelAccessList) |
400 | { | 566 | { |
401 | if (ResolveUserUuid(entry.AgentID)) | 567 | if (ResolveUserUuid(scene, entry.AgentID)) |
402 | accessList.Add(entry); | 568 | accessList.Add(entry); |
403 | // else, drop this access rule | 569 | // else, drop this access rule |
404 | } | 570 | } |
@@ -414,23 +580,24 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
414 | if (!m_merge) | 580 | if (!m_merge) |
415 | { | 581 | { |
416 | bool setupDefaultParcel = (landData.Count == 0); | 582 | bool setupDefaultParcel = (landData.Count == 0); |
417 | m_scene.LandChannel.Clear(setupDefaultParcel); | 583 | scene.LandChannel.Clear(setupDefaultParcel); |
418 | } | 584 | } |
419 | 585 | ||
420 | m_scene.EventManager.TriggerIncomingLandDataFromStorage(landData); | 586 | scene.EventManager.TriggerIncomingLandDataFromStorage(landData); |
421 | m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count); | 587 | m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count); |
422 | } | 588 | } |
423 | 589 | ||
424 | /// <summary> | 590 | /// <summary> |
425 | /// Look up the given user id to check whether it's one that is valid for this grid. | 591 | /// Look up the given user id to check whether it's one that is valid for this grid. |
426 | /// </summary> | 592 | /// </summary> |
593 | /// <param name="scene"></param> | ||
427 | /// <param name="uuid"></param> | 594 | /// <param name="uuid"></param> |
428 | /// <returns></returns> | 595 | /// <returns></returns> |
429 | private bool ResolveUserUuid(UUID uuid) | 596 | private bool ResolveUserUuid(Scene scene, UUID uuid) |
430 | { | 597 | { |
431 | if (!m_validUserUuids.ContainsKey(uuid)) | 598 | if (!m_validUserUuids.ContainsKey(uuid)) |
432 | { | 599 | { |
433 | UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); | 600 | UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid); |
434 | m_validUserUuids.Add(uuid, account != null); | 601 | m_validUserUuids.Add(uuid, account != null); |
435 | } | 602 | } |
436 | 603 | ||
@@ -485,7 +652,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
485 | string extension = filename.Substring(i); | 652 | string extension = filename.Substring(i); |
486 | string uuid = filename.Remove(filename.Length - extension.Length); | 653 | string uuid = filename.Remove(filename.Length - extension.Length); |
487 | 654 | ||
488 | if (m_scene.AssetService.GetMetadata(uuid) != null) | 655 | if (m_assetService.GetMetadata(uuid) != null) |
489 | { | 656 | { |
490 | // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid); | 657 | // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid); |
491 | return true; | 658 | return true; |
@@ -505,7 +672,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
505 | 672 | ||
506 | // We're relying on the asset service to do the sensible thing and not store the asset if it already | 673 | // We're relying on the asset service to do the sensible thing and not store the asset if it already |
507 | // exists. | 674 | // exists. |
508 | m_scene.AssetService.Store(asset); | 675 | m_assetService.Store(asset); |
509 | 676 | ||
510 | /** | 677 | /** |
511 | * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so | 678 | * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so |
@@ -533,12 +700,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
533 | /// <summary> | 700 | /// <summary> |
534 | /// Load region settings data | 701 | /// Load region settings data |
535 | /// </summary> | 702 | /// </summary> |
703 | /// <param name="scene"></param> | ||
536 | /// <param name="settingsPath"></param> | 704 | /// <param name="settingsPath"></param> |
537 | /// <param name="data"></param> | 705 | /// <param name="data"></param> |
706 | /// <param name="dearchivedScenes"></param> | ||
538 | /// <returns> | 707 | /// <returns> |
539 | /// true if settings were loaded successfully, false otherwise | 708 | /// true if settings were loaded successfully, false otherwise |
540 | /// </returns> | 709 | /// </returns> |
541 | private bool LoadRegionSettings(string settingsPath, byte[] data) | 710 | private bool LoadRegionSettings(Scene scene, string settingsPath, byte[] data, DearchiveScenesInfo dearchivedScenes) |
542 | { | 711 | { |
543 | RegionSettings loadedRegionSettings; | 712 | RegionSettings loadedRegionSettings; |
544 | 713 | ||
@@ -554,7 +723,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
554 | return false; | 723 | return false; |
555 | } | 724 | } |
556 | 725 | ||
557 | RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings; | 726 | RegionSettings currentRegionSettings = scene.RegionInfo.RegionSettings; |
558 | 727 | ||
559 | currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit; | 728 | currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit; |
560 | currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage; | 729 | currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage; |
@@ -591,12 +760,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
591 | foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints()) | 760 | foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints()) |
592 | currentRegionSettings.AddSpawnPoint(sp); | 761 | currentRegionSettings.AddSpawnPoint(sp); |
593 | 762 | ||
763 | currentRegionSettings.LoadedCreationDateTime = dearchivedScenes.LoadedCreationDateTime; | ||
764 | currentRegionSettings.LoadedCreationID = dearchivedScenes.GetOriginalRegionID(scene.RegionInfo.RegionID).ToString(); | ||
765 | |||
594 | currentRegionSettings.Save(); | 766 | currentRegionSettings.Save(); |
595 | 767 | ||
596 | m_scene.TriggerEstateSunUpdate(); | 768 | scene.TriggerEstateSunUpdate(); |
597 | 769 | ||
598 | IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); | 770 | IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>(); |
599 | |||
600 | if (estateModule != null) | 771 | if (estateModule != null) |
601 | estateModule.sendRegionHandshakeToAll(); | 772 | estateModule.sendRegionHandshakeToAll(); |
602 | 773 | ||
@@ -606,14 +777,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
606 | /// <summary> | 777 | /// <summary> |
607 | /// Load terrain data | 778 | /// Load terrain data |
608 | /// </summary> | 779 | /// </summary> |
780 | /// <param name="scene"></param> | ||
609 | /// <param name="terrainPath"></param> | 781 | /// <param name="terrainPath"></param> |
610 | /// <param name="data"></param> | 782 | /// <param name="data"></param> |
611 | /// <returns> | 783 | /// <returns> |
612 | /// true if terrain was resolved successfully, false otherwise. | 784 | /// true if terrain was resolved successfully, false otherwise. |
613 | /// </returns> | 785 | /// </returns> |
614 | private bool LoadTerrain(string terrainPath, byte[] data) | 786 | private bool LoadTerrain(Scene scene, string terrainPath, byte[] data) |
615 | { | 787 | { |
616 | ITerrainModule terrainModule = m_scene.RequestModuleInterface<ITerrainModule>(); | 788 | ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>(); |
617 | 789 | ||
618 | MemoryStream ms = new MemoryStream(data); | 790 | MemoryStream ms = new MemoryStream(data); |
619 | terrainModule.LoadFromStream(terrainPath, ms); | 791 | terrainModule.LoadFromStream(terrainPath, ms); |
@@ -629,17 +801,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
629 | /// </summary> | 801 | /// </summary> |
630 | /// <param name="path"></param> | 802 | /// <param name="path"></param> |
631 | /// <param name="data"></param> | 803 | /// <param name="data"></param> |
632 | public void LoadControlFile(string path, byte[] data) | 804 | /// <param name="dearchivedScenes"></param> |
805 | public DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes) | ||
633 | { | 806 | { |
634 | XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); | 807 | XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); |
635 | XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); | 808 | XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); |
636 | XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context); | 809 | XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context); |
637 | 810 | ||
638 | RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings; | 811 | // Loaded metadata will be empty if no information exists in the archive |
812 | dearchivedScenes.LoadedCreationDateTime = 0; | ||
813 | dearchivedScenes.DefaultOriginalID = ""; | ||
639 | 814 | ||
640 | // Loaded metadata will empty if no information exists in the archive | 815 | bool multiRegion = false; |
641 | currentRegionSettings.LoadedCreationDateTime = 0; | ||
642 | currentRegionSettings.LoadedCreationID = ""; | ||
643 | 816 | ||
644 | while (xtr.Read()) | 817 | while (xtr.Read()) |
645 | { | 818 | { |
@@ -665,18 +838,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
665 | { | 838 | { |
666 | int value; | 839 | int value; |
667 | if (Int32.TryParse(xtr.ReadElementContentAsString(), out value)) | 840 | if (Int32.TryParse(xtr.ReadElementContentAsString(), out value)) |
668 | currentRegionSettings.LoadedCreationDateTime = value; | 841 | dearchivedScenes.LoadedCreationDateTime = value; |
669 | } | 842 | } |
670 | else if (xtr.Name.ToString() == "id") | 843 | else if (xtr.Name.ToString() == "row") |
844 | { | ||
845 | multiRegion = true; | ||
846 | dearchivedScenes.StartRow(); | ||
847 | } | ||
848 | else if (xtr.Name.ToString() == "region") | ||
671 | { | 849 | { |
672 | currentRegionSettings.LoadedCreationID = xtr.ReadElementContentAsString(); | 850 | dearchivedScenes.StartRegion(); |
851 | } | ||
852 | else if (xtr.Name.ToString() == "id") | ||
853 | { | ||
854 | string id = xtr.ReadElementContentAsString(); | ||
855 | dearchivedScenes.DefaultOriginalID = id; | ||
856 | if (multiRegion) | ||
857 | dearchivedScenes.SetRegionOriginalID(id); | ||
858 | } | ||
859 | else if (xtr.Name.ToString() == "dir") | ||
860 | { | ||
861 | dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString()); | ||
673 | } | 862 | } |
674 | } | 863 | } |
675 | } | 864 | } |
676 | 865 | ||
677 | currentRegionSettings.Save(); | 866 | dearchivedScenes.MultiRegionFormat = multiRegion; |
678 | 867 | if (!multiRegion) | |
868 | { | ||
869 | // Add the single scene | ||
870 | dearchivedScenes.StartRow(); | ||
871 | dearchivedScenes.StartRegion(); | ||
872 | dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID); | ||
873 | dearchivedScenes.SetRegionDirectory(""); | ||
874 | } | ||
875 | |||
679 | ControlFileLoaded = true; | 876 | ControlFileLoaded = true; |
877 | |||
878 | return dearchivedScenes; | ||
680 | } | 879 | } |
681 | } | 880 | } |
682 | } \ No newline at end of file | 881 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs new file mode 100644 index 0000000..a66ed88 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | using OpenSim.Region.Framework.Scenes; | ||
33 | using OpenMetaverse; | ||
34 | using System.Drawing; | ||
35 | |||
36 | namespace OpenSim.Region.CoreModules.World.Archiver | ||
37 | { | ||
38 | /// <summary> | ||
39 | /// A group of regions arranged in a rectangle, possibly with holes. | ||
40 | /// </summary> | ||
41 | /// <remarks> | ||
42 | /// The regions usually (but not necessarily) belong to an archive file, in which case we | ||
43 | /// store additional information used to create the archive (e.g., each region's | ||
44 | /// directory within the archive). | ||
45 | /// </remarks> | ||
46 | public class ArchiveScenesGroup | ||
47 | { | ||
48 | /// <summary> | ||
49 | /// All the regions. The outer dictionary contains rows (key: Y coordinate). | ||
50 | /// The inner dictionaries contain each row's regions (key: X coordinate). | ||
51 | /// </summary> | ||
52 | public SortedDictionary<uint, SortedDictionary<uint, Scene>> Regions { get; set; } | ||
53 | |||
54 | /// <summary> | ||
55 | /// The subdirectory where each region is stored in the archive. | ||
56 | /// </summary> | ||
57 | protected Dictionary<UUID, string> m_regionDirs; | ||
58 | |||
59 | /// <summary> | ||
60 | /// The grid coordinates of the regions' bounding box. | ||
61 | /// </summary> | ||
62 | public Rectangle Rect { get; set; } | ||
63 | |||
64 | |||
65 | public ArchiveScenesGroup() | ||
66 | { | ||
67 | Regions = new SortedDictionary<uint, SortedDictionary<uint, Scene>>(); | ||
68 | m_regionDirs = new Dictionary<UUID, string>(); | ||
69 | Rect = new Rectangle(0, 0, 0, 0); | ||
70 | } | ||
71 | |||
72 | public void AddScene(Scene scene) | ||
73 | { | ||
74 | uint x = scene.RegionInfo.RegionLocX; | ||
75 | uint y = scene.RegionInfo.RegionLocY; | ||
76 | |||
77 | SortedDictionary<uint, Scene> row; | ||
78 | if (!Regions.TryGetValue(y, out row)) | ||
79 | { | ||
80 | row = new SortedDictionary<uint, Scene>(); | ||
81 | Regions[y] = row; | ||
82 | } | ||
83 | |||
84 | row[x] = scene; | ||
85 | } | ||
86 | |||
87 | /// <summary> | ||
88 | /// Called after all the scenes have been added. Performs calculations that require | ||
89 | /// knowledge of all the scenes. | ||
90 | /// </summary> | ||
91 | public void CalcSceneLocations() | ||
92 | { | ||
93 | if (Regions.Count == 0) | ||
94 | return; | ||
95 | |||
96 | // Find the bounding rectangle | ||
97 | |||
98 | uint firstY = Regions.First().Key; | ||
99 | uint lastY = Regions.Last().Key; | ||
100 | |||
101 | uint? firstX = null; | ||
102 | uint? lastX = null; | ||
103 | |||
104 | foreach (SortedDictionary<uint, Scene> row in Regions.Values) | ||
105 | { | ||
106 | uint curFirstX = row.First().Key; | ||
107 | uint curLastX = row.Last().Key; | ||
108 | |||
109 | firstX = (firstX == null) ? curFirstX : (firstX < curFirstX) ? firstX : curFirstX; | ||
110 | lastX = (lastX == null) ? curLastX : (lastX > curLastX) ? lastX : curLastX; | ||
111 | } | ||
112 | |||
113 | Rect = new Rectangle((int)firstX, (int)firstY, (int)(lastY - firstY + 1), (int)(lastX - firstX + 1)); | ||
114 | |||
115 | |||
116 | // Calculate the subdirectory in which each region will be stored in the archive | ||
117 | |||
118 | m_regionDirs.Clear(); | ||
119 | ForEachScene(delegate(Scene scene) | ||
120 | { | ||
121 | // We add the region's coordinates to ensure uniqueness even if multiple regions have the same name | ||
122 | string path = string.Format("{0}_{1}_{2}", | ||
123 | scene.RegionInfo.RegionLocX - Rect.X + 1, | ||
124 | scene.RegionInfo.RegionLocY - Rect.Y + 1, | ||
125 | scene.RegionInfo.RegionName.Replace(' ', '_')); | ||
126 | m_regionDirs[scene.RegionInfo.RegionID] = path; | ||
127 | }); | ||
128 | } | ||
129 | |||
130 | /// <summary> | ||
131 | /// Returns the subdirectory where the region is stored. | ||
132 | /// </summary> | ||
133 | /// <param name="regionID"></param> | ||
134 | /// <returns></returns> | ||
135 | public string GetRegionDir(UUID regionID) | ||
136 | { | ||
137 | return m_regionDirs[regionID]; | ||
138 | } | ||
139 | |||
140 | /// <summary> | ||
141 | /// Performs an action on all the scenes in this order: rows from South to North, | ||
142 | /// and within each row West to East. | ||
143 | /// </summary> | ||
144 | /// <param name="action"></param> | ||
145 | public void ForEachScene(Action<Scene> action) | ||
146 | { | ||
147 | foreach (SortedDictionary<uint, Scene> row in Regions.Values) | ||
148 | { | ||
149 | foreach (Scene scene in row.Values) | ||
150 | { | ||
151 | action(scene); | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /// <summary> | ||
157 | /// Returns the scene at position 'location'. | ||
158 | /// </summary> | ||
159 | /// <param name="location">A location in the grid</param> | ||
160 | /// <param name="scene">The scene at this location</param> | ||
161 | /// <returns>Whether the scene was found</returns> | ||
162 | public bool TryGetScene(Point location, out Scene scene) | ||
163 | { | ||
164 | SortedDictionary<uint, Scene> row; | ||
165 | if (Regions.TryGetValue((uint)location.Y, out row)) | ||
166 | { | ||
167 | if (row.TryGetValue((uint)location.X, out scene)) | ||
168 | return true; | ||
169 | } | ||
170 | |||
171 | scene = null; | ||
172 | return false; | ||
173 | } | ||
174 | |||
175 | } | ||
176 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs deleted file mode 100644 index 0780d86..0000000 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs +++ /dev/null | |||
@@ -1,153 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Xml; | ||
33 | using log4net; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Serialization; | ||
37 | using OpenSim.Framework.Serialization.External; | ||
38 | using OpenSim.Region.CoreModules.World.Terrain; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | |||
42 | namespace OpenSim.Region.CoreModules.World.Archiver | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Method called when all the necessary assets for an archive request have been received. | ||
46 | /// </summary> | ||
47 | public delegate void AssetsRequestCallback( | ||
48 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids); | ||
49 | |||
50 | /// <summary> | ||
51 | /// Execute the write of an archive once we have received all the necessary data | ||
52 | /// </summary> | ||
53 | public class ArchiveWriteRequestExecution | ||
54 | { | ||
55 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | protected ITerrainModule m_terrainModule; | ||
58 | protected IRegionSerialiserModule m_serialiser; | ||
59 | protected List<SceneObjectGroup> m_sceneObjects; | ||
60 | protected Scene m_scene; | ||
61 | protected TarArchiveWriter m_archiveWriter; | ||
62 | protected Guid m_requestId; | ||
63 | protected Dictionary<string, object> m_options; | ||
64 | |||
65 | public ArchiveWriteRequestExecution( | ||
66 | List<SceneObjectGroup> sceneObjects, | ||
67 | ITerrainModule terrainModule, | ||
68 | IRegionSerialiserModule serialiser, | ||
69 | Scene scene, | ||
70 | TarArchiveWriter archiveWriter, | ||
71 | Guid requestId, | ||
72 | Dictionary<string, object> options) | ||
73 | { | ||
74 | m_sceneObjects = sceneObjects; | ||
75 | m_terrainModule = terrainModule; | ||
76 | m_serialiser = serialiser; | ||
77 | m_scene = scene; | ||
78 | m_archiveWriter = archiveWriter; | ||
79 | m_requestId = requestId; | ||
80 | m_options = options; | ||
81 | } | ||
82 | |||
83 | protected internal void ReceivedAllAssets( | ||
84 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) | ||
85 | { | ||
86 | try | ||
87 | { | ||
88 | Save(assetsFoundUuids, assetsNotFoundUuids); | ||
89 | } | ||
90 | finally | ||
91 | { | ||
92 | m_archiveWriter.Close(); | ||
93 | } | ||
94 | |||
95 | m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_scene.RegionInfo.RegionName); | ||
96 | |||
97 | m_scene.EventManager.TriggerOarFileSaved(m_requestId, String.Empty); | ||
98 | } | ||
99 | |||
100 | protected internal void Save(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) | ||
101 | { | ||
102 | foreach (UUID uuid in assetsNotFoundUuids) | ||
103 | { | ||
104 | m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); | ||
105 | } | ||
106 | |||
107 | // m_log.InfoFormat( | ||
108 | // "[ARCHIVER]: Received {0} of {1} assets requested", | ||
109 | // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); | ||
110 | |||
111 | m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive."); | ||
112 | |||
113 | // Write out region settings | ||
114 | string settingsPath | ||
115 | = String.Format("{0}{1}.xml", ArchiveConstants.SETTINGS_PATH, m_scene.RegionInfo.RegionName); | ||
116 | m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(m_scene.RegionInfo.RegionSettings)); | ||
117 | |||
118 | m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive."); | ||
119 | |||
120 | // Write out land data (aka parcel) settings | ||
121 | List<ILandObject>landObjects = m_scene.LandChannel.AllParcels(); | ||
122 | foreach (ILandObject lo in landObjects) | ||
123 | { | ||
124 | LandData landData = lo.LandData; | ||
125 | string landDataPath = String.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH, | ||
126 | landData.GlobalID.ToString()); | ||
127 | m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); | ||
128 | } | ||
129 | |||
130 | m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive."); | ||
131 | |||
132 | // Write out terrain | ||
133 | string terrainPath | ||
134 | = String.Format("{0}{1}.r32", ArchiveConstants.TERRAINS_PATH, m_scene.RegionInfo.RegionName); | ||
135 | |||
136 | MemoryStream ms = new MemoryStream(); | ||
137 | m_terrainModule.SaveToStream(terrainPath, ms); | ||
138 | m_archiveWriter.WriteFile(terrainPath, ms.ToArray()); | ||
139 | ms.Close(); | ||
140 | |||
141 | m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive."); | ||
142 | |||
143 | // Write out scene object metadata | ||
144 | foreach (SceneObjectGroup sceneObject in m_sceneObjects) | ||
145 | { | ||
146 | //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType()); | ||
147 | |||
148 | string serializedObject = m_serialiser.SerializeGroupToXml2(sceneObject, m_options); | ||
149 | m_archiveWriter.WriteFile(ArchiveHelpers.CreateObjectPath(sceneObject), serializedObject); | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs index 4edaaca..2c34f4b 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs | |||
@@ -43,6 +43,7 @@ using OpenSim.Region.Framework.Scenes; | |||
43 | using Ionic.Zlib; | 43 | using Ionic.Zlib; |
44 | using GZipStream = Ionic.Zlib.GZipStream; | 44 | using GZipStream = Ionic.Zlib.GZipStream; |
45 | using CompressionMode = Ionic.Zlib.CompressionMode; | 45 | using CompressionMode = Ionic.Zlib.CompressionMode; |
46 | using OpenSim.Framework.Serialization.External; | ||
46 | 47 | ||
47 | namespace OpenSim.Region.CoreModules.World.Archiver | 48 | namespace OpenSim.Region.CoreModules.World.Archiver |
48 | { | 49 | { |
@@ -61,17 +62,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
61 | /// <summary> | 62 | /// <summary> |
62 | /// The maximum major version of OAR that we can write. | 63 | /// The maximum major version of OAR that we can write. |
63 | /// </summary> | 64 | /// </summary> |
64 | public static int MAX_MAJOR_VERSION = 0; | 65 | public static int MAX_MAJOR_VERSION = 1; |
66 | |||
67 | /// <summary> | ||
68 | /// Whether we're saving a multi-region archive. | ||
69 | /// </summary> | ||
70 | public bool MultiRegionFormat { get; set; } | ||
65 | 71 | ||
66 | /// <summary> | 72 | /// <summary> |
67 | /// Determine whether this archive will save assets. Default is true. | 73 | /// Determine whether this archive will save assets. Default is true. |
68 | /// </summary> | 74 | /// </summary> |
69 | public bool SaveAssets { get; set; } | 75 | public bool SaveAssets { get; set; } |
70 | 76 | ||
71 | protected ArchiverModule m_module; | 77 | /// <summary> |
72 | protected Scene m_scene; | 78 | /// Determines which objects will be included in the archive, according to their permissions. |
79 | /// Default is null, meaning no permission checks. | ||
80 | /// </summary> | ||
81 | public string CheckPermissions { get; set; } | ||
82 | |||
83 | protected Scene m_rootScene; | ||
73 | protected Stream m_saveStream; | 84 | protected Stream m_saveStream; |
85 | protected TarArchiveWriter m_archiveWriter; | ||
74 | protected Guid m_requestId; | 86 | protected Guid m_requestId; |
87 | protected Dictionary<string, object> m_options; | ||
75 | 88 | ||
76 | /// <summary> | 89 | /// <summary> |
77 | /// Constructor | 90 | /// Constructor |
@@ -82,7 +95,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
82 | /// <exception cref="System.IO.IOException"> | 95 | /// <exception cref="System.IO.IOException"> |
83 | /// If there was a problem opening a stream for the file specified by the savePath | 96 | /// If there was a problem opening a stream for the file specified by the savePath |
84 | /// </exception> | 97 | /// </exception> |
85 | public ArchiveWriteRequestPreparation(ArchiverModule module, string savePath, Guid requestId) : this(module, requestId) | 98 | public ArchiveWriteRequestPreparation(Scene scene, string savePath, Guid requestId) : this(scene, requestId) |
86 | { | 99 | { |
87 | try | 100 | try |
88 | { | 101 | { |
@@ -100,26 +113,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
100 | /// <summary> | 113 | /// <summary> |
101 | /// Constructor. | 114 | /// Constructor. |
102 | /// </summary> | 115 | /// </summary> |
103 | /// <param name="module">Calling module</param> | 116 | /// <param name="scene">The root scene to archive</param> |
104 | /// <param name="saveStream">The stream to which to save data.</param> | 117 | /// <param name="saveStream">The stream to which to save data.</param> |
105 | /// <param name="requestId">The id associated with this request</param> | 118 | /// <param name="requestId">The id associated with this request</param> |
106 | public ArchiveWriteRequestPreparation(ArchiverModule module, Stream saveStream, Guid requestId) : this(module, requestId) | 119 | public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId) |
107 | { | 120 | { |
108 | m_saveStream = saveStream; | 121 | m_saveStream = saveStream; |
109 | } | 122 | } |
110 | 123 | ||
111 | protected ArchiveWriteRequestPreparation(ArchiverModule module, Guid requestId) | 124 | protected ArchiveWriteRequestPreparation(Scene scene, Guid requestId) |
112 | { | 125 | { |
113 | m_module = module; | 126 | m_rootScene = scene; |
114 | |||
115 | // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix | ||
116 | // this. | ||
117 | if (m_module != null) | ||
118 | m_scene = m_module.Scene; | ||
119 | |||
120 | m_requestId = requestId; | 127 | m_requestId = requestId; |
128 | m_archiveWriter = null; | ||
121 | 129 | ||
130 | MultiRegionFormat = false; | ||
122 | SaveAssets = true; | 131 | SaveAssets = true; |
132 | CheckPermissions = null; | ||
123 | } | 133 | } |
124 | 134 | ||
125 | /// <summary> | 135 | /// <summary> |
@@ -128,126 +138,157 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
128 | /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> | 138 | /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> |
129 | public void ArchiveRegion(Dictionary<string, object> options) | 139 | public void ArchiveRegion(Dictionary<string, object> options) |
130 | { | 140 | { |
141 | m_options = options; | ||
142 | |||
143 | if (options.ContainsKey("all") && (bool)options["all"]) | ||
144 | MultiRegionFormat = true; | ||
145 | |||
131 | if (options.ContainsKey("noassets") && (bool)options["noassets"]) | 146 | if (options.ContainsKey("noassets") && (bool)options["noassets"]) |
132 | SaveAssets = false; | 147 | SaveAssets = false; |
133 | 148 | ||
149 | Object temp; | ||
150 | if (options.TryGetValue("checkPermissions", out temp)) | ||
151 | CheckPermissions = (string)temp; | ||
152 | |||
153 | |||
154 | // Find the regions to archive | ||
155 | ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup(); | ||
156 | if (MultiRegionFormat) | ||
157 | { | ||
158 | m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count); | ||
159 | SceneManager.Instance.ForEachScene(delegate(Scene scene) | ||
160 | { | ||
161 | scenesGroup.AddScene(scene); | ||
162 | }); | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | scenesGroup.AddScene(m_rootScene); | ||
167 | } | ||
168 | scenesGroup.CalcSceneLocations(); | ||
169 | |||
170 | |||
171 | m_archiveWriter = new TarArchiveWriter(m_saveStream); | ||
172 | |||
134 | try | 173 | try |
135 | { | 174 | { |
175 | // Write out control file. It should be first so that it will be found ASAP when loading the file. | ||
176 | m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup)); | ||
177 | m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); | ||
178 | |||
179 | // Archive the regions | ||
180 | |||
136 | Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>(); | 181 | Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>(); |
137 | 182 | ||
138 | EntityBase[] entities = m_scene.GetEntities(); | 183 | scenesGroup.ForEachScene(delegate(Scene scene) |
139 | List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); | ||
140 | |||
141 | string checkPermissions = null; | ||
142 | int numObjectsSkippedPermissions = 0; | ||
143 | Object temp; | ||
144 | if (options.TryGetValue("checkPermissions", out temp)) | ||
145 | checkPermissions = (string)temp; | ||
146 | |||
147 | // Filter entities so that we only have scene objects. | ||
148 | // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods | ||
149 | // end up having to do this | ||
150 | foreach (EntityBase entity in entities) | ||
151 | { | 184 | { |
152 | if (entity is SceneObjectGroup) | 185 | string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : ""; |
153 | { | 186 | ArchiveOneRegion(scene, regionDir, assetUuids); |
154 | SceneObjectGroup sceneObject = (SceneObjectGroup)entity; | 187 | }); |
155 | 188 | ||
156 | if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) | 189 | // Archive the assets |
157 | { | ||
158 | if (!CanUserArchiveObject(m_scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, checkPermissions)) | ||
159 | { | ||
160 | // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR. | ||
161 | ++numObjectsSkippedPermissions; | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | sceneObjects.Add(sceneObject); | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | 190 | ||
171 | if (SaveAssets) | 191 | if (SaveAssets) |
172 | { | 192 | { |
173 | UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService); | 193 | m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count); |
174 | 194 | ||
175 | foreach (SceneObjectGroup sceneObject in sceneObjects) | 195 | // Asynchronously request all the assets required to perform this archive operation |
176 | { | 196 | AssetsRequest ar |
177 | assetGatherer.GatherAssetUuids(sceneObject, assetUuids); | 197 | = new AssetsRequest( |
178 | } | 198 | new AssetsArchiver(m_archiveWriter), assetUuids, |
199 | m_rootScene.AssetService, m_rootScene.UserAccountService, | ||
200 | m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets); | ||
179 | 201 | ||
180 | m_log.DebugFormat( | 202 | Util.FireAndForget(o => ar.Execute()); |
181 | "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", | 203 | |
182 | sceneObjects.Count, assetUuids.Count); | 204 | // CloseArchive() will be called from ReceivedAllAssets() |
183 | } | 205 | } |
184 | else | 206 | else |
185 | { | 207 | { |
186 | m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); | 208 | m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); |
209 | CloseArchive(string.Empty); | ||
187 | } | 210 | } |
211 | } | ||
212 | catch (Exception e) | ||
213 | { | ||
214 | CloseArchive(e.Message); | ||
215 | throw; | ||
216 | } | ||
217 | } | ||
188 | 218 | ||
189 | if (numObjectsSkippedPermissions > 0) | ||
190 | { | ||
191 | m_log.DebugFormat( | ||
192 | "[ARCHIVER]: {0} scene objects skipped due to lack of permissions", | ||
193 | numObjectsSkippedPermissions); | ||
194 | } | ||
195 | 219 | ||
196 | // Make sure that we also request terrain texture assets | 220 | private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids) |
197 | RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings; | 221 | { |
198 | 222 | m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName); | |
199 | if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) | ||
200 | assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture; | ||
201 | |||
202 | if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) | ||
203 | assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture; | ||
204 | |||
205 | if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) | ||
206 | assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture; | ||
207 | |||
208 | if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) | ||
209 | assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture; | ||
210 | |||
211 | TarArchiveWriter archiveWriter = new TarArchiveWriter(m_saveStream); | ||
212 | |||
213 | // Asynchronously request all the assets required to perform this archive operation | ||
214 | ArchiveWriteRequestExecution awre | ||
215 | = new ArchiveWriteRequestExecution( | ||
216 | sceneObjects, | ||
217 | m_scene.RequestModuleInterface<ITerrainModule>(), | ||
218 | m_scene.RequestModuleInterface<IRegionSerialiserModule>(), | ||
219 | m_scene, | ||
220 | archiveWriter, | ||
221 | m_requestId, | ||
222 | options); | ||
223 | |||
224 | m_log.InfoFormat("[ARCHIVER]: Creating archive file. This may take some time."); | ||
225 | |||
226 | // Write out control file. This has to be done first so that subsequent loaders will see this file first | ||
227 | // XXX: I know this is a weak way of doing it since external non-OAR aware tar executables will not do this | ||
228 | archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options)); | ||
229 | m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); | ||
230 | 223 | ||
231 | if (SaveAssets) | 224 | EntityBase[] entities = scene.GetEntities(); |
225 | List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>(); | ||
226 | |||
227 | int numObjectsSkippedPermissions = 0; | ||
228 | |||
229 | // Filter entities so that we only have scene objects. | ||
230 | // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods | ||
231 | // end up having to do this | ||
232 | IPermissionsModule permissionsModule = scene.RequestModuleInterface<IPermissionsModule>(); | ||
233 | foreach (EntityBase entity in entities) | ||
234 | { | ||
235 | if (entity is SceneObjectGroup) | ||
232 | { | 236 | { |
233 | AssetsRequest ar | 237 | SceneObjectGroup sceneObject = (SceneObjectGroup)entity; |
234 | = new AssetsRequest( | ||
235 | new AssetsArchiver(archiveWriter), assetUuids, | ||
236 | m_scene.AssetService, m_scene.UserAccountService, | ||
237 | m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets); | ||
238 | 238 | ||
239 | Util.FireAndForget(o => ar.Execute()); | 239 | if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) |
240 | { | ||
241 | if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule)) | ||
242 | { | ||
243 | // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR. | ||
244 | ++numObjectsSkippedPermissions; | ||
245 | } | ||
246 | else | ||
247 | { | ||
248 | sceneObjects.Add(sceneObject); | ||
249 | } | ||
250 | } | ||
240 | } | 251 | } |
241 | else | 252 | } |
253 | |||
254 | if (SaveAssets) | ||
255 | { | ||
256 | UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService); | ||
257 | int prevAssets = assetUuids.Count; | ||
258 | |||
259 | foreach (SceneObjectGroup sceneObject in sceneObjects) | ||
242 | { | 260 | { |
243 | awre.ReceivedAllAssets(new List<UUID>(), new List<UUID>()); | 261 | assetGatherer.GatherAssetUuids(sceneObject, assetUuids); |
244 | } | 262 | } |
263 | |||
264 | m_log.DebugFormat( | ||
265 | "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", | ||
266 | sceneObjects.Count, assetUuids.Count - prevAssets); | ||
245 | } | 267 | } |
246 | catch (Exception) | 268 | |
269 | if (numObjectsSkippedPermissions > 0) | ||
247 | { | 270 | { |
248 | m_saveStream.Close(); | 271 | m_log.DebugFormat( |
249 | throw; | 272 | "[ARCHIVER]: {0} scene objects skipped due to lack of permissions", |
250 | } | 273 | numObjectsSkippedPermissions); |
274 | } | ||
275 | |||
276 | // Make sure that we also request terrain texture assets | ||
277 | RegionSettings regionSettings = scene.RegionInfo.RegionSettings; | ||
278 | |||
279 | if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1) | ||
280 | assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture; | ||
281 | |||
282 | if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2) | ||
283 | assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture; | ||
284 | |||
285 | if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3) | ||
286 | assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture; | ||
287 | |||
288 | if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4) | ||
289 | assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture; | ||
290 | |||
291 | Save(scene, sceneObjects, regionDir); | ||
251 | } | 292 | } |
252 | 293 | ||
253 | /// <summary> | 294 | /// <summary> |
@@ -256,14 +297,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
256 | /// <param name="user">The user</param> | 297 | /// <param name="user">The user</param> |
257 | /// <param name="objGroup">The object group</param> | 298 | /// <param name="objGroup">The object group</param> |
258 | /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param> | 299 | /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param> |
300 | /// <param name="permissionsModule">The scene's permissions module</param> | ||
259 | /// <returns>Whether the user is allowed to export the object to an OAR</returns> | 301 | /// <returns>Whether the user is allowed to export the object to an OAR</returns> |
260 | private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions) | 302 | private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule) |
261 | { | 303 | { |
262 | if (checkPermissions == null) | 304 | if (checkPermissions == null) |
263 | return true; | 305 | return true; |
264 | 306 | ||
265 | IPermissionsModule module = m_scene.RequestModuleInterface<IPermissionsModule>(); | 307 | if (permissionsModule == null) |
266 | if (module == null) | ||
267 | return true; // this shouldn't happen | 308 | return true; // this shouldn't happen |
268 | 309 | ||
269 | // Check whether the user is permitted to export all of the parts in the SOG. If any | 310 | // Check whether the user is permitted to export all of the parts in the SOG. If any |
@@ -275,7 +316,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
275 | foreach (SceneObjectPart obj in objGroup.Parts) | 316 | foreach (SceneObjectPart obj in objGroup.Parts) |
276 | { | 317 | { |
277 | uint perm; | 318 | uint perm; |
278 | PermissionClass permissionClass = module.GetPermissionClass(user, obj); | 319 | PermissionClass permissionClass = permissionsModule.GetPermissionClass(user, obj); |
279 | switch (permissionClass) | 320 | switch (permissionClass) |
280 | { | 321 | { |
281 | case PermissionClass.Owner: | 322 | case PermissionClass.Owner: |
@@ -330,16 +371,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
330 | } | 371 | } |
331 | 372 | ||
332 | /// <summary> | 373 | /// <summary> |
333 | /// Create the control file for the most up to date archive | 374 | /// Create the control file. |
334 | /// </summary> | 375 | /// </summary> |
335 | /// <returns></returns> | 376 | /// <returns></returns> |
336 | public string CreateControlFile(Dictionary<string, object> options) | 377 | public string CreateControlFile(ArchiveScenesGroup scenesGroup) |
337 | { | 378 | { |
338 | int majorVersion = MAX_MAJOR_VERSION, minorVersion = 8; | 379 | int majorVersion; |
380 | int minorVersion; | ||
381 | |||
382 | if (MultiRegionFormat) | ||
383 | { | ||
384 | majorVersion = MAX_MAJOR_VERSION; | ||
385 | minorVersion = 0; | ||
386 | } | ||
387 | else | ||
388 | { | ||
389 | // To support older versions of OpenSim, we continue to create single-region OARs | ||
390 | // using the old file format. In the future this format will be discontinued. | ||
391 | majorVersion = 0; | ||
392 | minorVersion = 8; | ||
393 | } | ||
339 | // | 394 | // |
340 | // if (options.ContainsKey("version")) | 395 | // if (m_options.ContainsKey("version")) |
341 | // { | 396 | // { |
342 | // string[] parts = options["version"].ToString().Split('.'); | 397 | // string[] parts = m_options["version"].ToString().Split('.'); |
343 | // if (parts.Length >= 1) | 398 | // if (parts.Length >= 1) |
344 | // { | 399 | // { |
345 | // majorVersion = Int32.Parse(parts[0]); | 400 | // majorVersion = Int32.Parse(parts[0]); |
@@ -368,10 +423,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
368 | // } | 423 | // } |
369 | 424 | ||
370 | m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion); | 425 | m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion); |
371 | //if (majorVersion == 1) | 426 | if (majorVersion == 1) |
372 | //{ | 427 | { |
373 | // m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim 0.7.0.2 and earlier. Please use the --version=0 option if you want to produce a compatible OAR"); | 428 | 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"); |
374 | //} | 429 | } |
375 | 430 | ||
376 | String s; | 431 | String s; |
377 | 432 | ||
@@ -389,50 +444,191 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
389 | DateTime now = DateTime.UtcNow; | 444 | DateTime now = DateTime.UtcNow; |
390 | TimeSpan t = now - new DateTime(1970, 1, 1); | 445 | TimeSpan t = now - new DateTime(1970, 1, 1); |
391 | xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); | 446 | xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); |
392 | xtw.WriteElementString("id", UUID.Random().ToString()); | 447 | if (!MultiRegionFormat) |
448 | xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString()); | ||
393 | xtw.WriteEndElement(); | 449 | xtw.WriteEndElement(); |
450 | |||
451 | xtw.WriteElementString("assets_included", SaveAssets.ToString()); | ||
394 | 452 | ||
395 | xtw.WriteStartElement("region_info"); | 453 | if (MultiRegionFormat) |
454 | { | ||
455 | WriteRegionsManifest(scenesGroup, xtw); | ||
456 | } | ||
457 | else | ||
458 | { | ||
459 | xtw.WriteStartElement("region_info"); | ||
460 | WriteRegionInfo(m_rootScene, xtw); | ||
461 | xtw.WriteEndElement(); | ||
462 | } | ||
396 | 463 | ||
397 | bool isMegaregion; | 464 | xtw.WriteEndElement(); |
398 | Vector2 size; | 465 | |
399 | IRegionCombinerModule rcMod = null; | 466 | xtw.Flush(); |
467 | } | ||
400 | 468 | ||
401 | // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix | 469 | s = sw.ToString(); |
402 | // this, possibly by doing control file creation somewhere else. | 470 | } |
403 | if (m_module != null) | ||
404 | rcMod = m_module.RegionCombinerModule; | ||
405 | 471 | ||
406 | if (rcMod != null) | 472 | return s; |
407 | isMegaregion = rcMod.IsRootForMegaregion(m_scene.RegionInfo.RegionID); | 473 | } |
408 | else | ||
409 | isMegaregion = false; | ||
410 | 474 | ||
411 | if (isMegaregion) | 475 | /// <summary> |
412 | size = rcMod.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); | 476 | /// Writes the list of regions included in a multi-region OAR. |
413 | else | 477 | /// </summary> |
414 | size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); | 478 | private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw) |
479 | { | ||
480 | xtw.WriteStartElement("regions"); | ||
415 | 481 | ||
416 | xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); | 482 | // Write the regions in order: rows from South to North, then regions from West to East. |
417 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); | 483 | // The list of regions can have "holes"; we write empty elements in their position. |
418 | 484 | ||
419 | xtw.WriteEndElement(); | 485 | for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y) |
420 | 486 | { | |
421 | xtw.WriteElementString("assets_included", SaveAssets.ToString()); | 487 | SortedDictionary<uint, Scene> row; |
488 | if (scenesGroup.Regions.TryGetValue(y, out row)) | ||
489 | { | ||
490 | xtw.WriteStartElement("row"); | ||
491 | |||
492 | for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x) | ||
493 | { | ||
494 | Scene scene; | ||
495 | if (row.TryGetValue(x, out scene)) | ||
496 | { | ||
497 | xtw.WriteStartElement("region"); | ||
498 | xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString()); | ||
499 | xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID)); | ||
500 | WriteRegionInfo(scene, xtw); | ||
501 | xtw.WriteEndElement(); | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | // Write a placeholder for a missing region | ||
506 | xtw.WriteElementString("region", ""); | ||
507 | } | ||
508 | } | ||
422 | 509 | ||
423 | xtw.WriteEndElement(); | 510 | xtw.WriteEndElement(); |
424 | |||
425 | xtw.Flush(); | ||
426 | } | 511 | } |
512 | else | ||
513 | { | ||
514 | // Write a placeholder for a missing row | ||
515 | xtw.WriteElementString("row", ""); | ||
516 | } | ||
517 | } | ||
427 | 518 | ||
428 | s = sw.ToString(); | 519 | xtw.WriteEndElement(); // "regions" |
520 | } | ||
521 | |||
522 | protected static void WriteRegionInfo(Scene scene, XmlTextWriter xtw) | ||
523 | { | ||
524 | bool isMegaregion; | ||
525 | Vector2 size; | ||
526 | |||
527 | IRegionCombinerModule rcMod = scene.RequestModuleInterface<IRegionCombinerModule>(); | ||
528 | |||
529 | if (rcMod != null) | ||
530 | isMegaregion = rcMod.IsRootForMegaregion(scene.RegionInfo.RegionID); | ||
531 | else | ||
532 | isMegaregion = false; | ||
533 | |||
534 | if (isMegaregion) | ||
535 | size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); | ||
536 | else | ||
537 | size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); | ||
538 | |||
539 | xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); | ||
540 | xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); | ||
541 | } | ||
542 | |||
543 | |||
544 | protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir) | ||
545 | { | ||
546 | if (regionDir != string.Empty) | ||
547 | regionDir = ArchiveConstants.REGIONS_PATH + regionDir + "/"; | ||
548 | |||
549 | m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive."); | ||
550 | |||
551 | // Write out region settings | ||
552 | string settingsPath = String.Format("{0}{1}{2}.xml", | ||
553 | regionDir, ArchiveConstants.SETTINGS_PATH, scene.RegionInfo.RegionName); | ||
554 | m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(scene.RegionInfo.RegionSettings)); | ||
555 | |||
556 | m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive."); | ||
557 | |||
558 | // Write out land data (aka parcel) settings | ||
559 | List<ILandObject> landObjects = scene.LandChannel.AllParcels(); | ||
560 | foreach (ILandObject lo in landObjects) | ||
561 | { | ||
562 | LandData landData = lo.LandData; | ||
563 | string landDataPath = String.Format("{0}{1}{2}.xml", | ||
564 | regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString()); | ||
565 | m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options)); | ||
429 | } | 566 | } |
430 | 567 | ||
431 | // if (m_scene != null) | 568 | m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive."); |
432 | // Console.WriteLine( | ||
433 | // "[ARCHIVE WRITE REQUEST PREPARATION]: Control file for {0} is: {1}", m_scene.RegionInfo.RegionName, s); | ||
434 | 569 | ||
435 | return s; | 570 | // Write out terrain |
571 | string terrainPath = String.Format("{0}{1}{2}.r32", | ||
572 | regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName); | ||
573 | |||
574 | MemoryStream ms = new MemoryStream(); | ||
575 | scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms); | ||
576 | m_archiveWriter.WriteFile(terrainPath, ms.ToArray()); | ||
577 | ms.Close(); | ||
578 | |||
579 | m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive."); | ||
580 | |||
581 | // Write out scene object metadata | ||
582 | IRegionSerialiserModule serializer = scene.RequestModuleInterface<IRegionSerialiserModule>(); | ||
583 | foreach (SceneObjectGroup sceneObject in sceneObjects) | ||
584 | { | ||
585 | //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType()); | ||
586 | |||
587 | string serializedObject = serializer.SerializeGroupToXml2(sceneObject, m_options); | ||
588 | string objectPath = string.Format("{0}{1}", regionDir, ArchiveHelpers.CreateObjectPath(sceneObject)); | ||
589 | m_archiveWriter.WriteFile(objectPath, serializedObject); | ||
590 | } | ||
436 | } | 591 | } |
592 | |||
593 | protected void ReceivedAllAssets( | ||
594 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids) | ||
595 | { | ||
596 | foreach (UUID uuid in assetsNotFoundUuids) | ||
597 | { | ||
598 | m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid); | ||
599 | } | ||
600 | |||
601 | // m_log.InfoFormat( | ||
602 | // "[ARCHIVER]: Received {0} of {1} assets requested", | ||
603 | // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); | ||
604 | |||
605 | CloseArchive(String.Empty); | ||
606 | } | ||
607 | |||
608 | |||
609 | /// <summary> | ||
610 | /// Closes the archive and notifies that we're done. | ||
611 | /// </summary> | ||
612 | /// <param name="errorMessage">The error that occurred, or empty for success</param> | ||
613 | protected void CloseArchive(string errorMessage) | ||
614 | { | ||
615 | try | ||
616 | { | ||
617 | if (m_archiveWriter != null) | ||
618 | m_archiveWriter.Close(); | ||
619 | m_saveStream.Close(); | ||
620 | } | ||
621 | catch (Exception e) | ||
622 | { | ||
623 | m_log.Error(string.Format("[ARCHIVER]: Error closing archive: {0} ", e.Message), e); | ||
624 | if (errorMessage == string.Empty) | ||
625 | errorMessage = e.Message; | ||
626 | } | ||
627 | |||
628 | m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_rootScene.RegionInfo.RegionName); | ||
629 | |||
630 | m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage); | ||
631 | } | ||
632 | |||
437 | } | 633 | } |
438 | } | 634 | } |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index bf3b124..26535a9 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs | |||
@@ -146,6 +146,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
146 | ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; }); | 146 | ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; }); |
147 | ops.Add("publish", v => options["wipe-owners"] = v != null); | 147 | ops.Add("publish", v => options["wipe-owners"] = v != null); |
148 | ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; }); | 148 | ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; }); |
149 | ops.Add("all", delegate(string v) { options["all"] = v != null; }); | ||
149 | 150 | ||
150 | List<string> mainParams = ops.Parse(cmdparams); | 151 | List<string> mainParams = ops.Parse(cmdparams); |
151 | 152 | ||
@@ -169,7 +170,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
169 | m_log.InfoFormat( | 170 | m_log.InfoFormat( |
170 | "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath); | 171 | "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath); |
171 | 172 | ||
172 | new ArchiveWriteRequestPreparation(this, savePath, requestId).ArchiveRegion(options); | 173 | new ArchiveWriteRequestPreparation(Scene, savePath, requestId).ArchiveRegion(options); |
173 | } | 174 | } |
174 | 175 | ||
175 | public void ArchiveRegion(Stream saveStream) | 176 | public void ArchiveRegion(Stream saveStream) |
@@ -184,7 +185,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
184 | 185 | ||
185 | public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options) | 186 | public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options) |
186 | { | 187 | { |
187 | new ArchiveWriteRequestPreparation(this, saveStream, requestId).ArchiveRegion(options); | 188 | new ArchiveWriteRequestPreparation(Scene, saveStream, requestId).ArchiveRegion(options); |
188 | } | 189 | } |
189 | 190 | ||
190 | public void DearchiveRegion(string loadPath) | 191 | public void DearchiveRegion(string loadPath) |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index a073cb9..5787279 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs | |||
@@ -46,6 +46,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
46 | { | 46 | { |
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | 48 | ||
49 | /// <summary> | ||
50 | /// Method called when all the necessary assets for an archive request have been received. | ||
51 | /// </summary> | ||
52 | public delegate void AssetsRequestCallback( | ||
53 | ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids); | ||
54 | |||
49 | enum RequestState | 55 | enum RequestState |
50 | { | 56 | { |
51 | Initial, | 57 | Initial, |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs new file mode 100644 index 0000000..3dcc020 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | using OpenSim.Region.Framework.Scenes; | ||
33 | using OpenMetaverse; | ||
34 | using System.Drawing; | ||
35 | using log4net; | ||
36 | using System.Reflection; | ||
37 | using OpenSim.Framework.Serialization; | ||
38 | |||
39 | namespace OpenSim.Region.CoreModules.World.Archiver | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// The regions included in an OAR file. | ||
43 | /// </summary> | ||
44 | public class DearchiveScenesInfo | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | /// <summary> | ||
49 | /// One region in the archive. | ||
50 | /// </summary> | ||
51 | public class RegionInfo | ||
52 | { | ||
53 | /// <summary> | ||
54 | /// The subdirectory in which the region is stored. | ||
55 | /// </summary> | ||
56 | public string Directory { get; set; } | ||
57 | |||
58 | /// <summary> | ||
59 | /// The region's coordinates (relative to the South-West corner of the block). | ||
60 | /// </summary> | ||
61 | public Point Location { get; set; } | ||
62 | |||
63 | /// <summary> | ||
64 | /// The UUID of the original scene from which this archived region was saved. | ||
65 | /// </summary> | ||
66 | public string OriginalID { get; set; } | ||
67 | |||
68 | /// <summary> | ||
69 | /// The scene in the current simulator into which this region is loaded. | ||
70 | /// If null then the region doesn't have a corresponding scene, and it won't be loaded. | ||
71 | /// </summary> | ||
72 | public Scene Scene { get; set; } | ||
73 | } | ||
74 | |||
75 | /// <summary> | ||
76 | /// Whether this archive uses the multi-region format. | ||
77 | /// </summary> | ||
78 | public Boolean MultiRegionFormat { get; set; } | ||
79 | |||
80 | /// <summary> | ||
81 | /// Maps (Region directory -> region) | ||
82 | /// </summary> | ||
83 | protected Dictionary<string, RegionInfo> m_directory2region = new Dictionary<string, RegionInfo>(); | ||
84 | |||
85 | /// <summary> | ||
86 | /// Maps (UUID of the scene in the simulator where the region will be loaded -> region) | ||
87 | /// </summary> | ||
88 | protected Dictionary<UUID, RegionInfo> m_newId2region = new Dictionary<UUID, RegionInfo>(); | ||
89 | |||
90 | public int LoadedCreationDateTime { get; set; } | ||
91 | public string DefaultOriginalID { get; set; } | ||
92 | |||
93 | // These variables are used while reading the archive control file | ||
94 | protected int? m_curY = null; | ||
95 | protected int? m_curX = null; | ||
96 | protected RegionInfo m_curRegion; | ||
97 | |||
98 | |||
99 | public DearchiveScenesInfo() | ||
100 | { | ||
101 | MultiRegionFormat = false; | ||
102 | } | ||
103 | |||
104 | |||
105 | // The following methods are used while reading the archive control file | ||
106 | |||
107 | public void StartRow() | ||
108 | { | ||
109 | m_curY = (m_curY == null) ? 0 : m_curY + 1; | ||
110 | m_curX = null; | ||
111 | } | ||
112 | |||
113 | public void StartRegion() | ||
114 | { | ||
115 | m_curX = (m_curX == null) ? 0 : m_curX + 1; | ||
116 | // Note: this doesn't mean we have a real region in this location; this could just be a "hole" | ||
117 | } | ||
118 | |||
119 | public void SetRegionOriginalID(string id) | ||
120 | { | ||
121 | m_curRegion = new RegionInfo(); | ||
122 | m_curRegion.Location = new Point((int)m_curX, (int)m_curY); | ||
123 | m_curRegion.OriginalID = id; | ||
124 | // 'curRegion' will be saved in 'm_directory2region' when SetRegionDir() is called | ||
125 | } | ||
126 | |||
127 | public void SetRegionDirectory(string directory) | ||
128 | { | ||
129 | m_curRegion.Directory = directory; | ||
130 | m_directory2region[directory] = m_curRegion; | ||
131 | } | ||
132 | |||
133 | |||
134 | /// <summary> | ||
135 | /// Sets all the scenes present in the simulator. | ||
136 | /// </summary> | ||
137 | /// <remarks> | ||
138 | /// This method matches regions in the archive to scenes in the simulator according to | ||
139 | /// their relative position. We only load regions if there's an existing Scene in the | ||
140 | /// grid location where the region should be loaded. | ||
141 | /// </remarks> | ||
142 | /// <param name="rootScene">The scene where the Load OAR operation was run</param> | ||
143 | /// <param name="simulatorScenes">All the scenes in the simulator</param> | ||
144 | public void SetSimulatorScenes(Scene rootScene, ArchiveScenesGroup simulatorScenes) | ||
145 | { | ||
146 | foreach (RegionInfo archivedRegion in m_directory2region.Values) | ||
147 | { | ||
148 | Point location = new Point((int)rootScene.RegionInfo.RegionLocX, (int)rootScene.RegionInfo.RegionLocY); | ||
149 | location.Offset(archivedRegion.Location); | ||
150 | |||
151 | Scene scene; | ||
152 | if (simulatorScenes.TryGetScene(location, out scene)) | ||
153 | { | ||
154 | archivedRegion.Scene = scene; | ||
155 | m_newId2region[scene.RegionInfo.RegionID] = archivedRegion; | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | m_log.WarnFormat("[ARCHIVER]: Not loading archived region {0} because there's no existing region at location {1},{2}", | ||
160 | archivedRegion.Directory, location.X, location.Y); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /// <summary> | ||
166 | /// Returns the archived region according to the path of a file in the archive. | ||
167 | /// Also, converts the full path into a path that is relative to the region's directory. | ||
168 | /// </summary> | ||
169 | /// <param name="fullPath">The path of a file in the archive</param> | ||
170 | /// <param name="scene">The corresponding Scene, or null if none</param> | ||
171 | /// <param name="relativePath">The path relative to the region's directory. (Or the original | ||
172 | /// path, if this file doesn't belong to a region.)</param> | ||
173 | /// <returns>True: use this file; False: skip it</returns> | ||
174 | public bool GetRegionFromPath(string fullPath, out Scene scene, out string relativePath) | ||
175 | { | ||
176 | scene = null; | ||
177 | relativePath = fullPath; | ||
178 | |||
179 | if (!MultiRegionFormat) | ||
180 | { | ||
181 | if (m_newId2region.Count > 0) | ||
182 | scene = m_newId2region.First().Value.Scene; | ||
183 | return true; | ||
184 | } | ||
185 | |||
186 | if (!fullPath.StartsWith(ArchiveConstants.REGIONS_PATH)) | ||
187 | return true; // this file doesn't belong to a region | ||
188 | |||
189 | string[] parts = fullPath.Split(new Char[] { '/' }, 3); | ||
190 | if (parts.Length != 3) | ||
191 | return false; | ||
192 | string regionDirectory = parts[1]; | ||
193 | relativePath = parts[2]; | ||
194 | |||
195 | RegionInfo region; | ||
196 | if (m_directory2region.TryGetValue(regionDirectory, out region)) | ||
197 | { | ||
198 | scene = region.Scene; | ||
199 | return (scene != null); | ||
200 | } | ||
201 | else | ||
202 | { | ||
203 | return false; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | /// <summary> | ||
208 | /// Returns the original UUID of a region (from the simulator where the OAR was saved), | ||
209 | /// given the UUID of the scene it was loaded into in the current simulator. | ||
210 | /// </summary> | ||
211 | /// <param name="newID"></param> | ||
212 | /// <returns></returns> | ||
213 | public string GetOriginalRegionID(UUID newID) | ||
214 | { | ||
215 | RegionInfo region; | ||
216 | if (m_newId2region.TryGetValue(newID, out region)) | ||
217 | return region.OriginalID; | ||
218 | else | ||
219 | return DefaultOriginalID; | ||
220 | } | ||
221 | |||
222 | /// <summary> | ||
223 | /// Returns the scenes that have been (or will be) loaded. | ||
224 | /// </summary> | ||
225 | /// <returns></returns> | ||
226 | public List<UUID> GetLoadedScenes() | ||
227 | { | ||
228 | return m_newId2region.Keys.ToList(); | ||
229 | } | ||
230 | |||
231 | } | ||
232 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 904110e..cfdfd8c 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs | |||
@@ -47,6 +47,7 @@ using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants; | |||
47 | using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; | 47 | using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; |
48 | using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; | 48 | using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; |
49 | using RegionSettings = OpenSim.Framework.RegionSettings; | 49 | using RegionSettings = OpenSim.Framework.RegionSettings; |
50 | using OpenSim.Region.Framework.Interfaces; | ||
50 | 51 | ||
51 | namespace OpenSim.Region.CoreModules.World.Archiver.Tests | 52 | namespace OpenSim.Region.CoreModules.World.Archiver.Tests |
52 | { | 53 | { |
@@ -70,9 +71,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
70 | 71 | ||
71 | m_scene = new SceneHelpers().SetupScene(); | 72 | m_scene = new SceneHelpers().SetupScene(); |
72 | SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule); | 73 | SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule); |
74 | |||
75 | new SceneManager(); | ||
76 | SceneManager.Instance.Add(m_scene); | ||
73 | } | 77 | } |
74 | 78 | ||
75 | private void LoadCompleted(Guid requestId, string errorMessage) | 79 | private void LoadCompleted(Guid requestId, List<UUID> loadedScenes, string errorMessage) |
76 | { | 80 | { |
77 | lock (this) | 81 | lock (this) |
78 | { | 82 | { |
@@ -186,7 +190,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
186 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 190 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
187 | 191 | ||
188 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 192 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); |
189 | arr.LoadControlFile(filePath, data); | 193 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
190 | 194 | ||
191 | Assert.That(arr.ControlFileLoaded, Is.True); | 195 | Assert.That(arr.ControlFileLoaded, Is.True); |
192 | 196 | ||
@@ -270,7 +274,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
270 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); | 274 | Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); |
271 | 275 | ||
272 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); | 276 | ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); |
273 | arr.LoadControlFile(filePath, data); | 277 | arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); |
274 | 278 | ||
275 | Assert.That(arr.ControlFileLoaded, Is.True); | 279 | Assert.That(arr.ControlFileLoaded, Is.True); |
276 | 280 | ||
@@ -307,7 +311,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
307 | 311 | ||
308 | tar.WriteFile( | 312 | tar.WriteFile( |
309 | ArchiveConstants.CONTROL_FILE_PATH, | 313 | ArchiveConstants.CONTROL_FILE_PATH, |
310 | new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); | 314 | new ArchiveWriteRequestPreparation(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); |
311 | 315 | ||
312 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); | 316 | SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); |
313 | SceneObjectPart sop2 | 317 | SceneObjectPart sop2 |
@@ -362,11 +366,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
362 | // Also check that direct entries which will also have a file entry containing that directory doesn't | 366 | // Also check that direct entries which will also have a file entry containing that directory doesn't |
363 | // upset load | 367 | // upset load |
364 | tar.WriteDir(ArchiveConstants.TERRAINS_PATH); | 368 | tar.WriteDir(ArchiveConstants.TERRAINS_PATH); |
365 | 369 | ||
366 | tar.WriteFile( | 370 | tar.WriteFile( |
367 | ArchiveConstants.CONTROL_FILE_PATH, | 371 | ArchiveConstants.CONTROL_FILE_PATH, |
368 | new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); | 372 | new ArchiveWriteRequestPreparation(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); |
369 | |||
370 | SceneObjectPart part1 = CreateSceneObjectPart1(); | 373 | SceneObjectPart part1 = CreateSceneObjectPart1(); |
371 | 374 | ||
372 | part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f); | 375 | part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f); |
@@ -519,6 +522,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
519 | TestScene scene2 = new SceneHelpers().SetupScene(); | 522 | TestScene scene2 = new SceneHelpers().SetupScene(); |
520 | SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); | 523 | SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); |
521 | 524 | ||
525 | SceneManager.Instance.Add(scene2); | ||
526 | |||
522 | // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is | 527 | // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is |
523 | // behaving correctly | 528 | // behaving correctly |
524 | UserAccountHelpers.CreateUserWithInventory(scene2, objectOwner); | 529 | UserAccountHelpers.CreateUserWithInventory(scene2, objectOwner); |
@@ -554,7 +559,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests | |||
554 | tar.WriteDir(ArchiveConstants.TERRAINS_PATH); | 559 | tar.WriteDir(ArchiveConstants.TERRAINS_PATH); |
555 | tar.WriteFile( | 560 | tar.WriteFile( |
556 | ArchiveConstants.CONTROL_FILE_PATH, | 561 | ArchiveConstants.CONTROL_FILE_PATH, |
557 | new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); | 562 | new ArchiveWriteRequestPreparation(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup())); |
558 | 563 | ||
559 | RegionSettings rs = new RegionSettings(); | 564 | RegionSettings rs = new RegionSettings(); |
560 | rs.AgentLimit = 17; | 565 | rs.AgentLimit = 17; |