AssetsRequest.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using System.Threading;
  31. using System.Timers;
  32. using log4net;
  33. using OpenMetaverse;
  34. using OpenSim.Framework;
  35. using OpenSim.Framework.Monitoring;
  36. using OpenSim.Framework.Serialization;
  37. using OpenSim.Framework.Serialization.External;
  38. using OpenSim.Services.Interfaces;
  39. namespace OpenSim.Region.CoreModules.World.Archiver
  40. {
  41. /// <summary>
  42. /// Encapsulate the asynchronous requests for the assets required for an archive operation
  43. /// </summary>
  44. class AssetsRequest
  45. {
  46. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  47. /// <summary>
  48. /// Method called when all the necessary assets for an archive request have been received.
  49. /// </summary>
  50. public delegate void AssetsRequestCallback(
  51. ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut);
  52. enum RequestState
  53. {
  54. Initial,
  55. Running,
  56. Completed,
  57. Aborted
  58. };
  59. /// <value>
  60. /// uuids to request
  61. /// </value>
  62. protected IDictionary<UUID, sbyte> m_uuids;
  63. private int m_previousErrorsCount;
  64. /// <value>
  65. /// Callback used when all the assets requested have been received.
  66. /// </value>
  67. protected AssetsRequestCallback m_assetsRequestCallback;
  68. /// <value>
  69. /// List of assets that were found. This will be passed back to the requester.
  70. /// </value>
  71. protected List<UUID> m_foundAssetUuids = new List<UUID>();
  72. /// <value>
  73. /// Maintain a list of assets that could not be found. This will be passed back to the requester.
  74. /// </value>
  75. protected List<UUID> m_notFoundAssetUuids = new List<UUID>();
  76. /// <value>
  77. /// Record the number of asset replies required so we know when we've finished
  78. /// </value>
  79. private int m_repliesRequired;
  80. private System.Timers.Timer m_timeOutTimer;
  81. private bool m_timeout;
  82. /// <value>
  83. /// Asset service used to request the assets
  84. /// </value>
  85. protected IAssetService m_assetService;
  86. protected IUserAccountService m_userAccountService;
  87. protected UUID m_scopeID; // the grid ID
  88. protected AssetsArchiver m_assetsArchiver;
  89. protected Dictionary<string, object> m_options;
  90. protected internal AssetsRequest(
  91. AssetsArchiver assetsArchiver, IDictionary<UUID, sbyte> uuids,
  92. int previousErrorsCount,
  93. IAssetService assetService, IUserAccountService userService,
  94. UUID scope, Dictionary<string, object> options,
  95. AssetsRequestCallback assetsRequestCallback)
  96. {
  97. m_assetsArchiver = assetsArchiver;
  98. m_uuids = uuids;
  99. m_previousErrorsCount = previousErrorsCount;
  100. m_assetsRequestCallback = assetsRequestCallback;
  101. m_assetService = assetService;
  102. m_userAccountService = userService;
  103. m_scopeID = scope;
  104. m_options = options;
  105. m_repliesRequired = uuids.Count;
  106. }
  107. protected internal void Execute()
  108. {
  109. Culture.SetCurrentCulture();
  110. // We can stop here if there are no assets to fetch
  111. if (m_repliesRequired == 0)
  112. {
  113. PerformAssetsRequestCallback(false);
  114. return;
  115. }
  116. m_timeOutTimer = new System.Timers.Timer(90000);
  117. m_timeOutTimer .AutoReset = false;
  118. m_timeOutTimer.Elapsed += OnTimeout;
  119. m_timeout = false;
  120. int gccontrol = 0;
  121. foreach (KeyValuePair<UUID, sbyte> kvp in m_uuids)
  122. {
  123. string thiskey = kvp.Key.ToString();
  124. try
  125. {
  126. m_timeOutTimer.Enabled = true;
  127. AssetBase asset = m_assetService.Get(thiskey);
  128. if(m_timeout)
  129. break;
  130. m_timeOutTimer.Enabled = false;
  131. if(asset == null)
  132. {
  133. m_notFoundAssetUuids.Add(new UUID(thiskey));
  134. continue;
  135. }
  136. sbyte assetType = kvp.Value;
  137. if (asset != null && assetType == (sbyte)AssetType.Unknown)
  138. {
  139. m_log.InfoFormat("[ARCHIVER]: Rewriting broken asset type for {0} to {1}", thiskey, SLUtil.AssetTypeFromCode(assetType));
  140. asset.Type = assetType;
  141. }
  142. m_foundAssetUuids.Add(asset.FullID);
  143. m_assetsArchiver.WriteAsset(PostProcess(asset));
  144. if(++gccontrol > 10000)
  145. {
  146. gccontrol = 0;
  147. GC.Collect();
  148. }
  149. }
  150. catch (Exception e)
  151. {
  152. m_log.ErrorFormat("[ARCHIVER]: Execute failed with {0}", e);
  153. }
  154. }
  155. m_timeOutTimer.Dispose();
  156. int totalerrors = m_notFoundAssetUuids.Count + m_previousErrorsCount;
  157. if(m_timeout)
  158. m_log.DebugFormat("[ARCHIVER]: Aborted because AssetService request timeout. Successfully added {0} assets", m_foundAssetUuids.Count);
  159. else if(totalerrors == 0)
  160. m_log.DebugFormat("[ARCHIVER]: Successfully added all {0} assets", m_foundAssetUuids.Count);
  161. else
  162. m_log.DebugFormat("[ARCHIVER]: Successfully added {0} assets ({1} of total possible assets requested were not found, were damaged or were not assets)",
  163. m_foundAssetUuids.Count, totalerrors);
  164. GC.Collect();
  165. PerformAssetsRequestCallback(m_timeout);
  166. }
  167. private void OnTimeout(object source, ElapsedEventArgs args)
  168. {
  169. m_timeout = true;
  170. }
  171. /// <summary>
  172. /// Perform the callback on the original requester of the assets
  173. /// </summary>
  174. private void PerformAssetsRequestCallback(object o)
  175. {
  176. if(m_assetsRequestCallback == null)
  177. return;
  178. Culture.SetCurrentCulture();
  179. Boolean timedOut = (Boolean)o;
  180. try
  181. {
  182. m_assetsRequestCallback(m_foundAssetUuids, m_notFoundAssetUuids, timedOut);
  183. }
  184. catch (Exception e)
  185. {
  186. m_log.ErrorFormat(
  187. "[ARCHIVER]: Terminating archive creation since asset requster callback failed with {0}", e);
  188. }
  189. }
  190. private AssetBase PostProcess(AssetBase asset)
  191. {
  192. if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home"))
  193. {
  194. //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID);
  195. string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), string.Empty, m_options["home"].ToString(), m_userAccountService, m_scopeID);
  196. asset.Data = Utils.StringToBytes(xml);
  197. }
  198. return asset;
  199. }
  200. }
  201. }