diff options
-rw-r--r-- | OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs | 73 |
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 |