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.
bulletsim
Justin Clark-Casey (justincc) 2011-08-16 21:03:43 +01:00
parent 0784791a44
commit 8c95c83562
1 changed files with 48 additions and 27 deletions

View File

@ -593,39 +593,60 @@ namespace Flotsam.RegionModules.AssetCache
try try
{ {
if (!Directory.Exists(directory)) try
{ {
Directory.CreateDirectory(directory); if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
stream = File.Open(tempname, FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(stream, asset);
}
catch (IOException e)
{
m_log.ErrorFormat(
"[FLOTSAM ASSET CACHE]: Failed to write asset {0} to temporary location {1} (final {2}) on cache in {3}. Exception {4} {5}.",
asset.ID, tempname, filename, directory, e.Message, e.StackTrace);
return;
}
finally
{
if (stream != null)
stream.Close();
} }
stream = File.Open(tempname, FileMode.Create); try
BinaryFormatter bformatter = new BinaryFormatter(); {
bformatter.Serialize(stream, asset); // Now that it's written, rename it so that it can be found.
stream.Close(); //
// File.Copy(tempname, filename, true);
// Now that it's written, rename it so that it can be found. // File.Delete(tempname);
// We're doing this as a file copy operation so that if two threads are competing to cache this asset, //
// then both suceed instead of one failing when it tries to move the file to a final filename that // For a brief period, this was done as a separate copy and then temporary file delete operation.
// already exists. // However, this causes exceptions on Windows when other threads attempt to read a file
// This assumes that the file copy operation is atomic. Assuming this holds, then copying also works // which is still being copied. So instead, go back to moving the file and swallowing any IOException
// if another simulator is using the same cache directory. // that occurs because two threads race to cache the same data (and the second fails because the file
File.Copy(tempname, filename, true); // already exists).
File.Delete(tempname); //
// This situation occurs fairly rarely anyway. We assume in this that moves are atomic on the
if (m_LogLevel >= 2) // filesystem.
m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID); File.Move(tempname, filename);
}
catch (Exception e) if (m_LogLevel >= 2)
{ m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Cache Stored :: {0}", asset.ID);
m_log.ErrorFormat( }
"[FLOTSAM ASSET CACHE]: Failed to write asset {0} to cache. Directory {1}, tempname {2}, filename {3}. Exception {4} {5}.", catch (IOException)
asset.ID, directory, tempname, filename, e.Message, e.StackTrace); {
// If we see an IOException here it's likely that some other competing thread has written the
// cache file first, so ignore. Other IOException errors (e.g. filesystem full) should be
// signally by the earlier temporary file writing code.
}
} }
finally finally
{ {
if (stream != null)
stream.Close();
// Even if the write fails with an exception, we need to make sure // Even if the write fails with an exception, we need to make sure
// that we release the lock on that file, otherwise it'll never get // that we release the lock on that file, otherwise it'll never get
// cached // cached