aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2011-08-16 21:03:43 +0100
committerJustin Clark-Casey (justincc)2011-08-16 21:03:43 +0100
commit8c95c83562db7e273cbf555514224773f21a2b19 (patch)
tree425b7f7fab6970779a444c62c07b3302a253c246
parentAdd "shutdown" message to RegionReady (diff)
downloadopensim-SC-8c95c83562db7e273cbf555514224773f21a2b19.zip
opensim-SC-8c95c83562db7e273cbf555514224773f21a2b19.tar.gz
opensim-SC-8c95c83562db7e273cbf555514224773f21a2b19.tar.bz2
opensim-SC-8c95c83562db7e273cbf555514224773f21a2b19.tar.xz
On Flotsam asset cache, go back to moving the file from the temporary location rather than copying.
Copying doesn't prevent IOExceptions on Windows due to file locking. (e.g. Mantis 5642, 5630). So instead go back to moving the file, swallowing IOExceptions that occur just for the move due to competing caching threads or even different opensimulator instances.
-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