Fix "save iar" hanging permanently if the asset request phase times out.

Unlike "save oar", this was happening on the same thread as the original request.
The timeout happens on another so the original thread is never aborted.
On "save oar" this leaves the thread hanging (still bad) but on "save iar" it left the console thread hanging.
Temporary fix is to make "save iar" do asset request on a separate thread, like "save oar".
Longer term fix will be to restructure asset save to use a ManualResetEvent rather than a separate timeout timer.
0.7.4-extended
Justin Clark-Casey (justincc) 2012-10-26 23:08:59 +01:00
parent c7c6c12146
commit d83df8c1cf
4 changed files with 33 additions and 14 deletions

View File

@ -337,11 +337,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
{ {
m_log.DebugFormat("[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetUuids.Count); m_log.DebugFormat("[INVENTORY ARCHIVER]: Saving {0} assets for items", m_assetUuids.Count);
new AssetsRequest( AssetsRequest ar
= new AssetsRequest(
new AssetsArchiver(m_archiveWriter), new AssetsArchiver(m_archiveWriter),
m_assetUuids, m_scene.AssetService, m_assetUuids, m_scene.AssetService,
m_scene.UserAccountService, m_scene.RegionInfo.ScopeID, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID,
options, ReceivedAllAssets).Execute(); options, ReceivedAllAssets);
Util.FireAndForget(o => ar.Execute());
} }
else else
{ {

View File

@ -83,6 +83,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
protected string m_item1Name = "Ray Gun Item"; protected string m_item1Name = "Ray Gun Item";
protected string m_coaItemName = "Coalesced Item"; protected string m_coaItemName = "Coalesced Item";
[TestFixtureSetUp]
public void FixtureSetup()
{
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
ConstructDefaultIarBytesForTestLoad();
}
[TestFixtureTearDown]
public void TearDown()
{
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
// tests really shouldn't).
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
}
[SetUp] [SetUp]
public override void SetUp() public override void SetUp()
{ {
@ -90,12 +108,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
m_iarStream = new MemoryStream(m_iarStreamBytes); m_iarStream = new MemoryStream(m_iarStreamBytes);
} }
[TestFixtureSetUp]
public void FixtureSetup()
{
ConstructDefaultIarBytesForTestLoad();
}
protected void ConstructDefaultIarBytesForTestLoad() protected void ConstructDefaultIarBytesForTestLoad()
{ {
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();

View File

@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
public void TestLoadCoalesecedItem() public void TestLoadCoalesecedItem()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password"); UserAccountHelpers.CreateUserWithInventory(m_scene, m_uaLL1, "password");
m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream); m_archiverModule.DearchiveInventory(m_uaLL1.FirstName, m_uaLL1.LastName, "/", "password", m_iarStream);

View File

@ -123,6 +123,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
m_options = options; m_options = options;
m_repliesRequired = uuids.Count; m_repliesRequired = uuids.Count;
// FIXME: This is a really poor way of handling the timeout since it will always leave the original requesting thread
// hanging. Need to restructure so an original request thread waits for a ManualResetEvent on asset received
// so we can properly abort that thread. Or request all assets synchronously, though that would be a more
// radical change
m_requestCallbackTimer = new System.Timers.Timer(TIMEOUT); m_requestCallbackTimer = new System.Timers.Timer(TIMEOUT);
m_requestCallbackTimer.AutoReset = false; m_requestCallbackTimer.AutoReset = false;
m_requestCallbackTimer.Elapsed += new ElapsedEventHandler(OnRequestCallbackTimeout); m_requestCallbackTimer.Elapsed += new ElapsedEventHandler(OnRequestCallbackTimeout);