From 5e8a13b2bfeaa3de193fbd265245d16fc9fb18b0 Mon Sep 17 00:00:00 2001 From: James South Date: Tue, 5 Mar 2013 17:20:24 +0000 Subject: [PATCH] cache updates Former-commit-id: 568501d80eb07e3dcbfafa603c1e3bc448291e1b --- src/ImageProcessor.Web/Caching/DiskCache.cs | 31 +++++++-------- .../Helpers/FileCompareLastwritetime.cs | 4 +- .../Helpers/{Class1.cs => ObjectFactory.cs} | 16 ++++---- .../HttpModules/ImageProcessingModule.cs | 38 ++++++++++--------- .../ImageFactoryExtensions.cs | 4 +- .../ImageProcessor.Web.csproj | 2 - 6 files changed, 48 insertions(+), 47 deletions(-) rename src/ImageProcessor.Web/Helpers/{Class1.cs => ObjectFactory.cs} (77%) diff --git a/src/ImageProcessor.Web/Caching/DiskCache.cs b/src/ImageProcessor.Web/Caching/DiskCache.cs index af3334939..e4abdee97 100644 --- a/src/ImageProcessor.Web/Caching/DiskCache.cs +++ b/src/ImageProcessor.Web/Caching/DiskCache.cs @@ -51,7 +51,7 @@ namespace ImageProcessor.Web.Caching /// NTFS Folder can handle up to 8000 files in a directory. /// This buffer will help us to ensure that we rarely hit anywhere near that limit. /// - private const int MaxFilesCount = 6000; + private const int MaxFilesCount = 6500; /// /// The regular expression to search strings for extension changes. @@ -177,8 +177,8 @@ namespace ImageProcessor.Web.Caching { lock (SyncRoot) { - DateTime dateTime = File.GetLastWriteTime(imagePath); - File.SetLastWriteTime(cachedImagePath, dateTime); + DateTime dateTime = File.GetLastWriteTimeUtc(imagePath); + File.SetLastWriteTimeUtc(cachedImagePath, dateTime); } } } @@ -202,11 +202,11 @@ namespace ImageProcessor.Web.Caching Parallel.ForEach( directoryInfos, - dir => + subDirectoryInfo => { // Get all the files in the cache ordered by LastAccessTime - oldest first. - List fileInfos = dir.EnumerateFiles("*", SearchOption.AllDirectories) - .OrderBy(x => x.LastAccessTime).ToList(); + List fileInfos = subDirectoryInfo.EnumerateFiles("*", SearchOption.AllDirectories) + .OrderBy(x => x.LastAccessTimeUtc).ToList(); int counter = fileInfos.Count; @@ -214,23 +214,24 @@ namespace ImageProcessor.Web.Caching fileInfos, fileInfo => { - lock (SyncRoot) + // Delete the file if we are nearing our limit buffer. + if (counter >= MaxFilesCount || fileInfo.LastAccessTimeUtc < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)) { - try + lock (SyncRoot) { - // Delete the file if we are nearing our limit buffer. - if (counter >= MaxFilesCount && fileInfo.LastAccessTime.ToUniversalTime() < DateTime.UtcNow.AddHours(1) - || fileInfo.LastAccessTime.ToUniversalTime() < DateTime.UtcNow.AddDays(-MaxFileCachedDuration)) + try { fileInfo.Delete(); counter -= 1; } - } - catch (IOException) - { - // Do Nothing, skip to the next. + catch (IOException) + { + // Do Nothing, skip to the next. + // TODO: Should we handle this? + } } } + }); }); } diff --git a/src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs b/src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs index 8b943e2e2..3aa938b8f 100644 --- a/src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs +++ b/src/ImageProcessor.Web/Helpers/FileCompareLastwritetime.cs @@ -43,7 +43,7 @@ namespace ImageProcessor.Web.Helpers /// true if the specified objects are equal; otherwise, false. public bool Equals(System.IO.FileInfo f1, System.IO.FileInfo f2) { - return ToMinute(f1.LastWriteTime.ToUniversalTime()) == ToMinute(f2.LastWriteTime.ToUniversalTime()); + return ToMinute(f1.LastWriteTimeUtc) == ToMinute(f2.LastWriteTimeUtc); } /// @@ -53,7 +53,7 @@ namespace ImageProcessor.Web.Helpers /// A hash code for the specified . public int GetHashCode(System.IO.FileInfo fi) { - return ToMinute(fi.LastWriteTime.ToUniversalTime()).GetHashCode(); + return ToMinute(fi.LastWriteTimeUtc).GetHashCode(); } } } diff --git a/src/ImageProcessor.Web/Helpers/Class1.cs b/src/ImageProcessor.Web/Helpers/ObjectFactory.cs similarity index 77% rename from src/ImageProcessor.Web/Helpers/Class1.cs rename to src/ImageProcessor.Web/Helpers/ObjectFactory.cs index 409a419e1..e13a6885a 100644 --- a/src/ImageProcessor.Web/Helpers/Class1.cs +++ b/src/ImageProcessor.Web/Helpers/ObjectFactory.cs @@ -17,13 +17,13 @@ namespace ImageProcessor.Web.Helpers Type type = ctor.DeclaringType; ParameterInfo[] paramsInfo = ctor.GetParameters(); - //create a single param of type object[] + // Create a single param of type object[] ParameterExpression param = Expression.Parameter(typeof(object[]), "args"); Expression[] argsExp = new Expression[paramsInfo.Length]; - //pick each arg from the params array - //and create a typed expression of them + // Pick each arg from the params array + // and create a typed expression for them for (int i = 0; i < paramsInfo.Length; i++) { Expression index = Expression.Constant(i); @@ -36,15 +36,15 @@ namespace ImageProcessor.Web.Helpers argsExp[i] = paramCastExp; } - //make a NewExpression that calls the - //ctor with the args we just created + // Make a NewExpression that calls the + // ctor with the args we just created NewExpression newExp = Expression.New(ctor, argsExp); - //create a lambda with the New - //Expression as body and our param object[] as arg + // Create a lambda with the New + // Expression as body and our param object[] as arg LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param); - //compile it + // Compile it ObjectActivator compiled = (ObjectActivator)lambda.Compile(); return compiled; } diff --git a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs index f0687d575..0cac04a94 100644 --- a/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs +++ b/src/ImageProcessor.Web/HttpModules/ImageProcessingModule.cs @@ -106,6 +106,16 @@ namespace ImageProcessor.Web.HttpModules if (ImageUtils.IsValidImageExtension(path) && !string.IsNullOrWhiteSpace(queryString)) { + // Check to see if this is the first run and if so run the cache controller. + if (isFirstRun) + { + // Trim the cache. + DiskCache.PurgeCachedFolders(); + + // Disable the controller. + isFirstRun = false; + } + string fullPath = string.Format("{0}?{1}", path, queryString); string imageName = Path.GetFileName(path); string cachedPath = DiskCache.GetCachePath(fullPath, imageName); @@ -117,16 +127,6 @@ namespace ImageProcessor.Web.HttpModules if ((exists == false) || (!isRemote && updated)) { - // Check to see if this is the first run and if so run the cache controller. - if (isFirstRun) - { - // Trim the cache. - DiskCache.PurgeCachedFolders(); - - // Disable the controller. - isFirstRun = false; - } - // Process the image. using (ImageFactory imageFactory = new ImageFactory()) { @@ -171,20 +171,22 @@ namespace ImageProcessor.Web.HttpModules // Ensure that the LastWriteTime property of the source and cached file match. DiskCache.SetCachedLastWriteTime(path, cachedPath); - - // If the number of cached imaged hits the maximum allowed for this session then we clear - // the cache again and reset the counter - if (cachedImageCounter >= DiskCache.MaxRunsBeforeCacheClear) - { - DiskCache.PurgeCachedFolders(); - cachedImageCounter = 0; - } } context.Items[CachedResponseTypeKey] = ImageUtils.GetResponseType(imageName).ToDescription(); // The cached file is valid so just rewrite the path. context.RewritePath(DiskCache.GetVirtualPath(cachedPath, context.Request), false); + + // If the number of cached imaged hits the maximum allowed for this session then we clear + // the cache again and reset the counter. + // TODO: There is a potential concurrency issue here but collision probability is very low# + // it would be nice to nail it though. + if (cachedImageCounter >= DiskCache.MaxRunsBeforeCacheClear) + { + DiskCache.PurgeCachedFolders(); + cachedImageCounter = 0; + } } } } diff --git a/src/ImageProcessor.Web/ImageFactoryExtensions.cs b/src/ImageProcessor.Web/ImageFactoryExtensions.cs index d135cbb67..2feff79fd 100644 --- a/src/ImageProcessor.Web/ImageFactoryExtensions.cs +++ b/src/ImageProcessor.Web/ImageFactoryExtensions.cs @@ -19,7 +19,7 @@ namespace ImageProcessor.Web /// public static class ImageFactoryExtensions { - private static readonly object SyncLock = new object(); + private static readonly object SyncRoot = new object(); /// /// Auto processes image files based on any querystring parameters added to the image path. @@ -36,7 +36,7 @@ public static ImageFactory AutoProcess(this ImageFactory factory) if (factory.ShouldProcess) { // TODO: This is going to be a bottleneck for speed. Find a faster way. - lock (SyncLock) + lock (SyncRoot) { // Get a list of all graphics processors that have parsed and matched the querystring. List list = diff --git a/src/ImageProcessor.Web/ImageProcessor.Web.csproj b/src/ImageProcessor.Web/ImageProcessor.Web.csproj index eefeb8952..6f5589cf3 100644 --- a/src/ImageProcessor.Web/ImageProcessor.Web.csproj +++ b/src/ImageProcessor.Web/ImageProcessor.Web.csproj @@ -56,8 +56,6 @@ - -