aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs73
1 files changed, 47 insertions, 26 deletions
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index abfc771..b2f6e13 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -593,39 +593,60 @@ namespace Flotsam.RegionModules.AssetCache
593 593
594 try 594 try
595 { 595 {
596 if (!Directory.Exists(directory)) 596 try
597 { 597 {
598 Directory.CreateDirectory(directory); 598 if (!Directory.Exists(directory))
599 {
600 Directory.CreateDirectory(directory);
601 }
602
603 stream = File.Open(tempname, FileMode.Create);
604 BinaryFormatter bformatter = new BinaryFormatter();
605 bformatter.Serialize(stream, asset);
599 } 606 }
607 catch (IOException e)
608 {
609 m_log.ErrorFormat(
610 "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.",
611 asset.ID, tempname, filename, directory, e.Message, e.StackTrace);
600 612
601 stream = File.Open(tempname, FileMode.Create); 613 return;
602 BinaryFormatter bformatter = new BinaryFormatter(); 614 }
603 bformatter.Serialize(stream, asset); 615 finally
604 stream.Close(); 616 {
605 617 if (stream != null)
606 // Now that it's written, rename it so that it can be found. 618 stream.Close();
607 // We're doing this as a file copy operation so that if two threads are competing to cache this asset, 619 }
608 // then both suceed instead of one failing when it tries to move the file to a final filename that
609 // already exists.
610 // This assumes that the file copy operation is atomic. Assuming this holds, then copying also works
611 // if another simulator is using the same cache directory.
612 File.Copy(tempname, filename, true);
613 File.Delete(tempname);
614 620
615 if (m_LogLevel >= 2) 621 try
616 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID); 622 {
617 } 623 // Now that it's written, rename it so that it can be found.
618 catch (Exception e) 624 //
619 { 625 // File.Copy(tempname, filename, true);
620 m_log.ErrorFormat( 626 // File.Delete(tempname);
621 "[FLOTSAM ASSET CACHE]: Failed to write asset {0} to cache. Directory {1}, tempname {2}, filename {3}. Exception {4} {5}.", 627 //
622 asset.ID, directory, tempname, filename, e.Message, e.StackTrace); 628 // For a brief period, this was done as a separate copy and then temporary file delete operation.
629 // However, this causes exceptions on Windows when other threads attempt to read a file
630 // which is still being copied. So instead, go back to moving the file and swallowing any IOException
631 // that occurs because two threads race to cache the same data (and the second fails because the file
632 // already exists).
633 //
634 // This situation occurs fairly rarely anyway. We assume in this that moves are atomic on the
635 // filesystem.
636 File.Move(tempname, filename);
637
638 if (m_LogLevel >= 2)
639 m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID);
640 }
641 catch (IOException)
642 {
643 // If we see an IOException here it's likely that some other competing thread has written the
644 // cache file first, so ignore. Other IOException errors (e.g. filesystem full) should be
645 // signally by the earlier temporary file writing code.
646 }
623 } 647 }
624 finally 648 finally
625 { 649 {
626 if (stream != null)
627 stream.Close();
628
629 // Even if the write fails with an exception, we need to make sure 650 // Even if the write fails with an exception, we need to make sure
630 // that we release the lock on that file, otherwise it'll never get 651 // that we release the lock on that file, otherwise it'll never get
631 // cached 652 // cached