From e9cbdaad7648d7750bbb7bb928b1ce7529a7e830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Aracsi?= Date: Wed, 4 Oct 2023 14:31:08 +0200 Subject: [PATCH 1/4] Fixing exception thrown caused by multiple threads attempting to access the same file simultaneously. --- CombinedResourceManager.cs | 28 ++++++++++++++++++++++++---- Services/CacheFileService.cs | 23 ++++++++++++++++++++--- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/CombinedResourceManager.cs b/CombinedResourceManager.cs index 473185f..1a03863 100644 --- a/CombinedResourceManager.cs +++ b/CombinedResourceManager.cs @@ -19,6 +19,7 @@ using Piedone.Combinator.Services; using System.Linq; using Piedone.HelpfulLibraries.Utilities; +using System.IO; namespace Piedone.Combinator { @@ -103,11 +104,30 @@ public override IList BuildRequiredResources(string str DiscoverResourceOverrides(resources, resourceType); - IList result; + IList result = null; - if (resourceType == ResourceType.Style) result = _combinatorService.CombineStylesheets(resources, settings); - else if (resourceType == ResourceType.JavaScript) result = _combinatorService.CombineScripts(resources, settings); - else return base.BuildRequiredResources(stringResourceType); + for (int retry = 0; retry < 3; retry++) + { + try + { + if (resourceType == ResourceType.Style) result = _combinatorService.CombineStylesheets(resources, settings); + else if (resourceType == ResourceType.JavaScript) result = _combinatorService.CombineScripts(resources, settings); + else return base.BuildRequiredResources(stringResourceType); + + break; + } + catch (Exception ex) + { + if (retry < 2) + { + System.Threading.Thread.Sleep(100); + } + else + { + throw ex; + } + } + } RemoveOriginalResourceShapes(result, resourceType); diff --git a/Services/CacheFileService.cs b/Services/CacheFileService.cs index 1e42bdb..f4c589f 100644 --- a/Services/CacheFileService.cs +++ b/Services/CacheFileService.cs @@ -18,6 +18,7 @@ using Piedone.Combinator.Models; using Autofac; using System.Web.Mvc; +using System.Resources; namespace Piedone.Combinator.Services { @@ -111,10 +112,26 @@ public void Save(string fingerprint, CombinatorResource resource, ICombinatorSet if (_storageProvider.FileExists(path)) _storageProvider.DeleteFile(path); - using (var stream = _storageProvider.CreateFile(path).OpenWrite()) + + for (int retry = 0; retry < 3; retry++) { - var bytes = Encoding.UTF8.GetBytes(resource.Content); - stream.Write(bytes, 0, bytes.Length); + try + { + using (var stream = _storageProvider.CreateFile(path).OpenWrite()) + { + var bytes = Encoding.UTF8.GetBytes(resource.Content); + stream.Write(bytes, 0, bytes.Length); + } + + break; + } + catch (Exception ex) + { + if (retry < 2) + Thread.Sleep(100); + else + throw ex; + } } if (!resource.IsRemoteStorageResource) From 0c7cdcbc63f51687444bbca1ae6741134aaa3375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Aracsi?= Date: Wed, 4 Oct 2023 23:14:21 +0200 Subject: [PATCH 2/4] Minor changes. --- CombinedResourceManager.cs | 15 ++++++--------- Services/CacheFileService.cs | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/CombinedResourceManager.cs b/CombinedResourceManager.cs index 1a03863..19ee3ab 100644 --- a/CombinedResourceManager.cs +++ b/CombinedResourceManager.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using Autofac.Features.Metadata; -using Orchard.Caching; +using Autofac.Features.Metadata; using Orchard.ContentManagement; // For generic ContentManager methods using Orchard.DisplayManagement.Descriptors; using Orchard.DisplayManagement.Descriptors.ResourceBindingStrategy; @@ -13,13 +9,14 @@ using Orchard.Settings; using Orchard.Themes; using Orchard.UI.Resources; -using Piedone.Combinator.EventHandlers; using Piedone.Combinator.Extensions; using Piedone.Combinator.Models; using Piedone.Combinator.Services; -using System.Linq; using Piedone.HelpfulLibraries.Utilities; -using System.IO; +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Threading; namespace Piedone.Combinator { @@ -120,7 +117,7 @@ public override IList BuildRequiredResources(string str { if (retry < 2) { - System.Threading.Thread.Sleep(100); + Thread.Sleep(100); } else { diff --git a/Services/CacheFileService.cs b/Services/CacheFileService.cs index f4c589f..158fc71 100644 --- a/Services/CacheFileService.cs +++ b/Services/CacheFileService.cs @@ -1,24 +1,21 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; +using Autofac; using Orchard; using Orchard.Caching; using Orchard.Data; using Orchard.Environment; using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; -using Orchard.Exceptions; using Orchard.FileSystems.Media; -using Orchard.Mvc; using Orchard.Services; using Piedone.Combinator.EventHandlers; using Piedone.Combinator.Extensions; using Piedone.Combinator.Models; -using Autofac; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; using System.Web.Mvc; -using System.Resources; namespace Piedone.Combinator.Services { From 34d238667ad295cb70275e9b4350d723254370d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Aracsi?= Date: Wed, 20 Dec 2023 14:02:09 +0100 Subject: [PATCH 3/4] Using simple semaphore (Mutex) to resolve concurrency issue instead of retry logic. --- CombinedResourceManager.cs | 20 +++++-------- Services/CacheFileService.cs | 54 +++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/CombinedResourceManager.cs b/CombinedResourceManager.cs index 19ee3ab..08d34fb 100644 --- a/CombinedResourceManager.cs +++ b/CombinedResourceManager.cs @@ -15,6 +15,7 @@ using Piedone.HelpfulLibraries.Utilities; using System; using System.Collections.Generic; +using System.IO; using System.Text.RegularExpressions; using System.Threading; @@ -101,28 +102,21 @@ public override IList BuildRequiredResources(string str DiscoverResourceOverrides(resources, resourceType); - IList result = null; + IList result; - for (int retry = 0; retry < 3; retry++) + using (var mutex = new Mutex(initiallyOwned: false, "Global\\CombinatorFileAccess")) { + mutex.WaitOne(); + try { if (resourceType == ResourceType.Style) result = _combinatorService.CombineStylesheets(resources, settings); else if (resourceType == ResourceType.JavaScript) result = _combinatorService.CombineScripts(resources, settings); else return base.BuildRequiredResources(stringResourceType); - - break; } - catch (Exception ex) + finally { - if (retry < 2) - { - Thread.Sleep(100); - } - else - { - throw ex; - } + mutex.ReleaseMutex(); } } diff --git a/Services/CacheFileService.cs b/Services/CacheFileService.cs index 158fc71..2c5f526 100644 --- a/Services/CacheFileService.cs +++ b/Services/CacheFileService.cs @@ -12,6 +12,7 @@ using Piedone.Combinator.Models; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading; @@ -109,9 +110,10 @@ public void Save(string fingerprint, CombinatorResource resource, ICombinatorSet if (_storageProvider.FileExists(path)) _storageProvider.DeleteFile(path); - - for (int retry = 0; retry < 3; retry++) + using (var mutex = new Mutex(initiallyOwned: false, "Global\\CombinatorFileAccess")) { + mutex.WaitOne(); + try { using (var stream = _storageProvider.CreateFile(path).OpenWrite()) @@ -119,17 +121,12 @@ public void Save(string fingerprint, CombinatorResource resource, ICombinatorSet var bytes = Encoding.UTF8.GetBytes(resource.Content); stream.Write(bytes, 0, bytes.Length); } - - break; } - catch (Exception ex) + finally { - if (retry < 2) - Thread.Sleep(100); - else - throw ex; + mutex.ReleaseMutex(); } - } + } if (!resource.IsRemoteStorageResource) { @@ -148,11 +145,23 @@ public void Save(string fingerprint, CombinatorResource resource, ICombinatorSet var relativeUrlsBaseUri = settings.ResourceBaseUri != null ? settings.ResourceBaseUri : new Uri(_urlHelper.RequestContext.HttpContext.Request.Url, _urlHelper.Content("~/")); ResourceProcessingService.RegexConvertRelativeUrlsToAbsolute(testResource, relativeUrlsBaseUri); - using (var stream = _storageProvider.CreateFile(path).OpenWrite()) + using (var mutex = new Mutex(initiallyOwned: false, "Global\\CombinatorFileAccess")) { - var bytes = Encoding.UTF8.GetBytes(testResource.Content); - stream.Write(bytes, 0, bytes.Length); - } + mutex.WaitOne(); + + try + { + using (var stream = _storageProvider.CreateFile(path).OpenWrite()) + { + var bytes = Encoding.UTF8.GetBytes(testResource.Content); + stream.Write(bytes, 0, bytes.Length); + } + } + finally + { + mutex.ReleaseMutex(); + } + } resource.IsRemoteStorageResource = true; fileRecord.Settings = _combinatorResourceManager.SerializeResourceSettings(resource); @@ -252,9 +261,22 @@ public void WriteSpriteStream(string fileName, SpriteStreamWriter streamWriter) if (_storageProvider.FileExists(path)) _storageProvider.DeleteFile(path); var spriteFile = _storageProvider.CreateFile(path); var publicUrl = _storageProvider.GetPublicUrl(path); - using (var stream = spriteFile.OpenWrite()) + + using (var mutex = new Mutex(initiallyOwned: false, "Global\\CombinatorFileAccess")) { - streamWriter(stream, publicUrl); + mutex.WaitOne(); + + try + { + using (var stream = spriteFile.OpenWrite()) + { + streamWriter(stream, publicUrl); + } + } + finally + { + mutex.ReleaseMutex(); + } } } From 0887b18933885d6f7ed24f334766a800a82c546d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Aracsi?= Date: Wed, 20 Dec 2023 14:05:03 +0100 Subject: [PATCH 4/4] Remove and sort usings. --- CombinedResourceManager.cs | 1 - Services/CacheFileService.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/CombinedResourceManager.cs b/CombinedResourceManager.cs index 08d34fb..eda457c 100644 --- a/CombinedResourceManager.cs +++ b/CombinedResourceManager.cs @@ -15,7 +15,6 @@ using Piedone.HelpfulLibraries.Utilities; using System; using System.Collections.Generic; -using System.IO; using System.Text.RegularExpressions; using System.Threading; diff --git a/Services/CacheFileService.cs b/Services/CacheFileService.cs index 2c5f526..5194964 100644 --- a/Services/CacheFileService.cs +++ b/Services/CacheFileService.cs @@ -12,7 +12,6 @@ using Piedone.Combinator.Models; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Text; using System.Threading;