aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2014-10-20 23:46:34 +0100
committerJustin Clark-Casey (justincc)2014-11-25 23:21:38 +0000
commit1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8 (patch)
treef8abd87d29a07bb6baf3c82d2824ff070a316aaa
parentAdd regression test TestPostAssetRewrite() to check results of HGAssetMapper.... (diff)
downloadopensim-SC-1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8.zip
opensim-SC-1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8.tar.gz
opensim-SC-1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8.tar.bz2
opensim-SC-1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8.tar.xz
When inserting missing CreatorData in the HGAssetMapper, do the rewrite on a streaming xml basis rather than loading it all into memory via XmlDocument.
This is because objects with lots of parts can have a lot of xml to load into memory, and this has been seen to have a noticeable performance impact. Whereas streaming has been seen to reduce the impact in normal serialization. Implmentation is messy but I couldn't see a better way of doing it when you can't assume that you know the exact structure of the input XML.
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs215
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs1
2 files changed, 185 insertions, 31 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
index 04615a9..2ac1517 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs
@@ -189,50 +189,203 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
189 return Utils.StringToBytes(RewriteSOP(xml)); 189 return Utils.StringToBytes(RewriteSOP(xml));
190 } 190 }
191 191
192 protected string RewriteSOP(string xml) 192 protected void TransformXml(XmlReader reader, XmlWriter writer)
193 { 193 {
194 XmlDocument doc = new XmlDocument(); 194// m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML");
195 doc.LoadXml(xml);
196 XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart");
197 195
198 foreach (XmlNode sop in sops) 196 int sopDepth = -1;
197 UserAccount creator = null;
198 bool hasCreatorData = false;
199
200 while (reader.Read())
199 { 201 {
200 UserAccount creator = null; 202 //Console.WriteLine("Depth: {0}", reader.Depth);
201 bool hasCreatorData = false; 203
202 XmlNodeList nodes = sop.ChildNodes; 204 switch (reader.NodeType)
203 foreach (XmlNode node in nodes)
204 { 205 {
205 if (node.Name == "CreatorID") 206 case XmlNodeType.Attribute:
207 writer.WriteAttributeString(reader.Prefix, reader.Name, reader.NamespaceURI, reader.Value);
208 break;
209
210 case XmlNodeType.CDATA:
211 writer.WriteCData(reader.Value);
212 break;
213
214 case XmlNodeType.Comment:
215 writer.WriteComment(reader.Value);
216 break;
217
218 case XmlNodeType.DocumentType:
219 writer.WriteDocType(reader.Name, reader.Value, null, null);
220 break;
221
222 case XmlNodeType.Element:
223// m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name);
224
225 writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
226
227 if (reader.LocalName == "SceneObjectPart")
206 { 228 {
207 UUID uuid = UUID.Zero; 229 if (sopDepth < 0)
208 UUID.TryParse(node.InnerText, out uuid); 230 {
209 creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); 231 sopDepth = reader.Depth;
232// m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth);
233 }
234 }
235 else
236 {
237 if (sopDepth >= 0 && reader.Depth == sopDepth + 1)
238 {
239 if (reader.Name == "CreatorID")
240 {
241 reader.Read();
242 if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID")
243 {
244 reader.Read();
245
246 if (reader.NodeType == XmlNodeType.Text)
247 {
248 UUID uuid = UUID.Zero;
249 UUID.TryParse(reader.Value, out uuid);
250 creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
251 writer.WriteElementString("UUID", reader.Value);
252 reader.Read();
253 }
254 else
255 {
256 // If we unexpected run across mixed content in this node, still carry on
257 // transforming the subtree (this replicates earlier behaviour).
258 TransformXml(reader, writer);
259 }
260 }
261 else
262 {
263 // If we unexpected run across mixed content in this node, still carry on
264 // transforming the subtree (this replicates earlier behaviour).
265 TransformXml(reader, writer);
266 }
267 }
268 else if (reader.Name == "CreatorData")
269 {
270 reader.Read();
271 if (reader.NodeType == XmlNodeType.Text)
272 {
273 hasCreatorData = true;
274 writer.WriteString(reader.Value);
275 }
276 else
277 {
278 // If we unexpected run across mixed content in this node, still carry on
279 // transforming the subtree (this replicates earlier behaviour).
280 TransformXml(reader, writer);
281 }
282 }
283 }
284 }
285
286 if (reader.IsEmptyElement)
287 {
288// m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name);
289 writer.WriteEndElement();
210 } 290 }
211 if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty)
212 hasCreatorData = true;
213
214 //if (node.Name == "OwnerID")
215 //{
216 // UserAccount owner = GetUser(node.InnerText);
217 // if (owner != null)
218 // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName;
219 //}
220 }
221 291
222 if (!hasCreatorData && creator != null) 292 break;
223 { 293
224 XmlElement creatorData = doc.CreateElement("CreatorData"); 294 case XmlNodeType.EndElement:
225 creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName; 295// m_log.DebugFormat("Depth {0} at EndElement", reader.Depth);
226 sop.AppendChild(creatorData); 296 if (sopDepth == reader.Depth)
297 {
298 if (!hasCreatorData && creator != null)
299 writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", m_HomeURI, creator.FirstName, creator.LastName));
300
301// m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth");
302 sopDepth = -1;
303 creator = null;
304 hasCreatorData = false;
305 }
306 writer.WriteEndElement();
307 break;
308
309 case XmlNodeType.EntityReference:
310 writer.WriteEntityRef(reader.Name);
311 break;
312
313 case XmlNodeType.ProcessingInstruction:
314 writer.WriteProcessingInstruction(reader.Name, reader.Value);
315 break;
316
317 case XmlNodeType.Text:
318 writer.WriteString(reader.Value);
319 break;
320
321 default:
322 m_log.WarnFormat("[HG ASSET MAPPER]: Unrecognized node in asset XML transform in {0}", m_scene.Name);
323 break;
227 } 324 }
228 } 325 }
326 }
327
328 protected string RewriteSOP(string xmlData)
329 {
330// Console.WriteLine("Input XML [{0}]", xmlData);
229 331
230 using (StringWriter wr = new StringWriter()) 332 using (StringWriter sw = new StringWriter())
333 using (XmlTextWriter writer = new XmlTextWriter(sw))
334 using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
335 using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
231 { 336 {
232 doc.Save(wr); 337 TransformXml(reader, writer);
233 return wr.ToString(); 338
339 writer.WriteEndDocument();
340
341// Console.WriteLine("Output: [{0}]", sw.ToString());
342
343 return sw.ToString();
234 } 344 }
235 345
346 // We are now taking the more complex streaming approach above because some assets can be very large
347 // and can trigger higher CPU use or possibly memory problems.
348// XmlDocument doc = new XmlDocument();
349// doc.LoadXml(xml);
350// XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart");
351//
352// foreach (XmlNode sop in sops)
353// {
354// UserAccount creator = null;
355// bool hasCreatorData = false;
356// XmlNodeList nodes = sop.ChildNodes;
357// foreach (XmlNode node in nodes)
358// {
359// if (node.Name == "CreatorID")
360// {
361// UUID uuid = UUID.Zero;
362// UUID.TryParse(node.InnerText, out uuid);
363// creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
364// }
365// if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty)
366// hasCreatorData = true;
367//
368// //if (node.Name == "OwnerID")
369// //{
370// // UserAccount owner = GetUser(node.InnerText);
371// // if (owner != null)
372// // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName;
373// //}
374// }
375//
376// if (!hasCreatorData && creator != null)
377// {
378// XmlElement creatorData = doc.CreateElement("CreatorData");
379// creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName;
380// sop.AppendChild(creatorData);
381// }
382// }
383//
384// using (StringWriter wr = new StringWriter())
385// {
386// doc.Save(wr);
387// return wr.ToString();
388// }
236 } 389 }
237 390
238 // TODO: unused 391 // TODO: unused
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs
index 3dbddfb..779da43 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs
@@ -44,6 +44,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
44 public void TestPostAssetRewrite() 44 public void TestPostAssetRewrite()
45 { 45 {
46 TestHelpers.InMethod(); 46 TestHelpers.InMethod();
47// TestHelpers.EnableLogging();
47 48
48 string homeUrl = "http://hg.HomeTestPostAssetRewriteGrid.com"; 49 string homeUrl = "http://hg.HomeTestPostAssetRewriteGrid.com";
49 string foreignUrl = "http://hg.ForeignTestPostAssetRewriteGrid.com"; 50 string foreignUrl = "http://hg.ForeignTestPostAssetRewriteGrid.com";