ImageResizer  3.4.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events
Public Member Functions | Protected Member Functions | Protected Attributes | Properties | List of all members
ImageResizer.Plugins.DiskCache.CleanupWorker Class Reference
Inheritance diagram for ImageResizer.Plugins.DiskCache.CleanupWorker:
Inheritance graph
[legend]
Collaboration diagram for ImageResizer.Plugins.DiskCache.CleanupWorker:
Collaboration graph
[legend]

Public Member Functions

 CleanupWorker (ILoggerProvider lp, CleanupStrategy cs, CleanupQueue queue, CustomDiskCache cache)
 Creates and starts a thread that consumes the queue, pausing until notified when 'queue' empties. More...
 
void MayHaveWork ()
 Tells the worker to check the queue for more work. More...
 
void BeLazy ()
 Tells the worker to avoid work for a little bit. More...
 
override IEnumerable< IIssueGetIssues ()
 Returns a copy of the list of reported issues. More...
 
void Dispose ()
 
void FlushAccessedDate (CleanupWorkItem item)
 
- Public Member Functions inherited from ImageResizer.Configuration.Issues.IssueSink
 IssueSink (string defaultSource)
 
virtual void AcceptIssue (IIssue i)
 Adds the specified issue to the list unless it is an exact duplicate of another instance. More...
 

Protected Member Functions

void main ()
 Thread runs this method. More...
 
void mainInner ()
 Processes work items from the queue, using at most 50% More...
 
bool DoWorkFor (TimeSpan length)
 Processes items from the queue for roughly the specified amount of time. Returns false if the queue was empty. More...
 
void DoTask (CleanupWorkItem item)
 
string addSlash (string s, bool physical)
 
void PopulateFolder (CleanupWorkItem item, bool recursive)
 
void RemoveFile (CleanupWorkItem item)
 
void CleanFolder (CleanupWorkItem item, bool recursvie)
 

Protected Attributes

long lastFoundItemsOverMax = DateTime.MinValue.Ticks
 The last time a cache folder exceeded both the optimum and maximum limits for file count. If recent, indicates a misconfiguration; the subfolders="" count needs to be increased. More...
 
long lastBusy = DateTime.MinValue.Ticks
 The last time a cache query came through More...
 
long lastWorked = DateTime.MinValue.Ticks
 The last time we did work (or attempted to do work, failing if the queue was empty) More...
 
bool otherProcessManagingCleanup = false
 When true, indicates that another process is managing cleanup operations - this thread is idle, waiting for the other process to end before it can pick up work. More...
 
readonly object _timesLock = new object()
 
volatile bool shuttingDown = false
 
- Protected Attributes inherited from ImageResizer.Configuration.Issues.IssueSink
string defaultSource = null
 

Properties

bool ExteralProcessCleaning [get]
 When true, indicates that another process is managing cleanup operations - this thread is idle, waiting for the other process to end before it can pick up work. More...
 

Detailed Description

Definition at line 14 of file CleanupWorker.cs.

Constructor & Destructor Documentation

ImageResizer.Plugins.DiskCache.CleanupWorker.CleanupWorker ( ILoggerProvider  lp,
CleanupStrategy  cs,
CleanupQueue  queue,
CustomDiskCache  cache 
)
inline

Creates and starts a thread that consumes the queue, pausing until notified when 'queue' empties.

Parameters
cs
queue
cache

Definition at line 29 of file CleanupWorker.cs.

29  :base("DiskCache-CleanupWorker") {
30  this.cs = cs;
31  this.queue = queue;
32  this.cache = cache;
33  this.lp = lp;
34  t = new Thread(main);
35  t.IsBackground = true;
36  t.Start();
37  }
void main()
Thread runs this method.

Member Function Documentation

void ImageResizer.Plugins.DiskCache.CleanupWorker.BeLazy ( )
inline

Tells the worker to avoid work for a little bit.

Definition at line 58 of file CleanupWorker.cs.

58  {
59  lock(_timesLock) lastBusy = DateTime.UtcNow.Ticks;
60 
61  }
long lastBusy
The last time a cache query came through
bool ImageResizer.Plugins.DiskCache.CleanupWorker.DoWorkFor ( TimeSpan  length)
inlineprotected

Processes items from the queue for roughly the specified amount of time. Returns false if the queue was empty.

Parameters
length
Returns

Definition at line 210 of file CleanupWorker.cs.

210  {
211  if (queue.IsEmpty) return false;
212 
213  DateTime startedAt = DateTime.UtcNow;
214  //Proccess as many items from the queue as possible
215  while (DateTime.UtcNow.Subtract(startedAt) < length && !queue.IsEmpty) {
216  //Check for shutdown
217  if (shuttingDown) return true;
218  try {
219  DoTask(queue.Pop());
220  } catch (Exception e) {
221  if (Debugger.IsAttached) throw;
222  if (lp.Logger != null) lp.Logger.Error("Failed exeuting task {0}", e.Message + e.StackTrace);
223  this.AcceptIssue(new Issue("Failed exeuting task", e.Message + e.StackTrace, IssueSeverity.Critical));
224  }
225  }
226  return true;
227  }
override IEnumerable<IIssue> ImageResizer.Plugins.DiskCache.CleanupWorker.GetIssues ( )
inlinevirtual

Returns a copy of the list of reported issues.

Returns

Reimplemented from ImageResizer.Configuration.Issues.IssueSink.

Definition at line 190 of file CleanupWorker.cs.

190  {
191  List<IIssue> issues = new List<IIssue>(base.GetIssues());
193  issues.Add(new Issue("An external process indicates it is managing cleanup of the disk cache. " +
194  "This process is not currently managing disk cache cleanup. If configured as a web garden, keep in mind that the negligible performance gains are likely to be outweighed by the loss of cache optimization quality.", IssueSeverity.Warning));
195  lock (_timesLock) {
196  if (this.lastFoundItemsOverMax > (DateTime.UtcNow.Subtract(new TimeSpan(0, 5, 0)).Ticks))
197  issues.Add(new Issue("Your cache configuration may not be optimal. If this message persists, you should increase the 'subfolders' value in the <diskcache /> element in Web.config",
198  "In the last 5 minutes, a cache folder exceeded both the optimum and maximum limits for file count. This usually indicates that your 'subfolders' setting is too low, and that cached images are being deleted shortly after their creation. \n" +
199  "To estimate the appropriate subfolders value, multiply the total number of images on the site times the average number of size variations, and divide by 400. I.e, 6,400 images with 2 variants would be 32. If in doubt, set the value higher, but ensure there is disk space available.", IssueSeverity.Error));
200 
201  }
202  return issues;
203  }
bool ExteralProcessCleaning
When true, indicates that another process is managing cleanup operations - this thread is idle...
long lastFoundItemsOverMax
The last time a cache folder exceeded both the optimum and maximum limits for file count...
void ImageResizer.Plugins.DiskCache.CleanupWorker.main ( )
inlineprotected

Thread runs this method.

Definition at line 79 of file CleanupWorker.cs.

79  {
80  try {
81  mainInner();
82  } catch (Exception ex) {
83  if (Debugger.IsAttached) throw;
84  if (lp.Logger != null) lp.Logger.Error("Contact support! A critical (and unexpected) exception occured in the disk cache cleanup worker thread. This needs to be investigated. {0}", ex.Message + ex.StackTrace);
85  this.AcceptIssue(new Issue("Contact support! A critical (and unexpected) exception occured in the disk cache cleanup worker thread. This needs to be investigated. ", ex.Message + ex.StackTrace, IssueSeverity.Critical));
86  }
87  }
void mainInner()
Processes work items from the queue, using at most 50%
void ImageResizer.Plugins.DiskCache.CleanupWorker.mainInner ( )
inlineprotected

Processes work items from the queue, using at most 50%

Definition at line 91 of file CleanupWorker.cs.

91  {
92  //TODO: Verify that GetHashCode() is the same between .net 2 and 4.
93  string mutexKey = "ir.cachedir:" + cache.PhysicalCachePath.ToLowerInvariant().GetHashCode().ToString("x", NumberFormatInfo.InvariantInfo);
94 
95  //Sleep for the duration requested before trying anything.
96  _quitWait.WaitOne(cs.StartupDelay);
97 
98  Mutex cleanupLock = null;
99  bool hasLock = false;
100 
101  try {
102  //Try to create and lock the mutex, or else open and lock it.
103  try{
104  cleanupLock = new Mutex(true, mutexKey, out hasLock);
105  }catch(UnauthorizedAccessException){
106  hasLock = false;
107  }
108 
109  //Start the work loop
110  while (true) {
111  //Check for shutdown
112  if (shuttingDown) return;
113 
114  //Try to acquire a reference to the lock if we didn't have access last time.
115  if (cleanupLock == null) {
116  //In this case, another process (running as another user account) has opened the lock. Eventually it may be garbage collected.
117  try {
118  cleanupLock = new Mutex(true, mutexKey, out hasLock);
119  } catch (UnauthorizedAccessException) {
120  hasLock = false;
121  }
122  }
123 
124  otherProcessManagingCleanup = !hasLock;
125  if (!hasLock) {
126  //If we have a reference, Wait until the other process calls ReleaseMutex(), or for 30 seconds, whichever is shorter.
127  if (cleanupLock != null) hasLock = cleanupLock.WaitOne(30000);
128  else Thread.Sleep(10000); //Otherwise just sleep 10s and check again, waiting for the mutex to be garbage collected so we can recreate it.
129  }
130  otherProcessManagingCleanup = !hasLock;
131  if (!hasLock) {
132  //Still no luck, someone else is managing things...
133  //Clear out the todo-list
134  queue.Clear();
135  //Get back to doing nothing.
136  continue;
137  }
138 
139 
140  //Is it time to do some work?
141  bool noWorkInTooLong = false; //Has it been too long since we did something?
142  lock (_timesLock) noWorkInTooLong = (DateTime.UtcNow.Subtract(new DateTime(lastWorked)) > cs.MaxDelay);
143 
144  bool notBusy = false; //Is the server busy recently?
145  lock (_timesLock) notBusy = (DateTime.UtcNow.Subtract(new DateTime(lastBusy)) > cs.MinDelay);
146  //doSomeWork keeps being true in absence of incoming requests
147 
148  //If the server isn't busy, or if this worker has been lazy to long long, do some work and time it.
149  Stopwatch workedForTime = null;
150  if (noWorkInTooLong || notBusy) {
151  workedForTime = new Stopwatch();
152  workedForTime.Start();
154  lock (_timesLock) lastWorked = DateTime.UtcNow.Ticks;
155  workedForTime.Stop();
156  }
157 
158  //Check for shutdown
159  if (shuttingDown) return;
160 
161 
162  //Nothing to do, queue is empty.
163  if (queue.IsEmpty)
164  //Wait perpetually until notified of more queue items.
165  _queueWait.WaitOne();
166  else if (notBusy)
167  //Don't flood the system even when it's not busy. 50% usage here. Wait for the length of time worked or the optimal work time, whichever is longer.
168  //A directory listing can take 30 seconds sometimes and kill the cpu.
169  _quitWait.WaitOne((int)Math.Max(cs.OptimalWorkSegmentLength.TotalMilliseconds, workedForTime.ElapsedMilliseconds));
170 
171  else {
172  //Estimate how long before we can run more code.
173  long busyTicks = 0;
174  lock (_timesLock) busyTicks = (cs.MinDelay - DateTime.UtcNow.Subtract(new DateTime(lastBusy))).Ticks;
175  long maxTicks = 0;
176  lock (_timesLock) maxTicks = (cs.MaxDelay - DateTime.UtcNow.Subtract(new DateTime(lastWorked))).Ticks;
177  //Use the longer value and add a second to avoid rounding and timing errors.
178  _quitWait.WaitOne(new TimeSpan(Math.Max(busyTicks, maxTicks)) + new TimeSpan(0, 0, 1));
179  }
180 
181  //Check for shutdown
182  if (shuttingDown) return;
183  }
184  } finally {
185  if (hasLock) cleanupLock.ReleaseMutex();
187  }
188  }
long lastWorked
The last time we did work (or attempted to do work, failing if the queue was empty) ...
long lastBusy
The last time a cache query came through
TimeSpan OptimalWorkSegmentLength
The optimal length for a work segment. Not always achieved.
Width and height are considered maximum values. The resulting image may be smaller to maintain its as...
bool otherProcessManagingCleanup
When true, indicates that another process is managing cleanup operations - this thread is idle...
bool DoWorkFor(TimeSpan length)
Processes items from the queue for roughly the specified amount of time. Returns false if the queue w...
void ImageResizer.Plugins.DiskCache.CleanupWorker.MayHaveWork ( )
inline

Tells the worker to check the queue for more work.

Definition at line 41 of file CleanupWorker.cs.

41  {
42  _queueWait.Set();
43  }

Member Data Documentation

long ImageResizer.Plugins.DiskCache.CleanupWorker.lastBusy = DateTime.MinValue.Ticks
protected

The last time a cache query came through

Definition at line 54 of file CleanupWorker.cs.

long ImageResizer.Plugins.DiskCache.CleanupWorker.lastFoundItemsOverMax = DateTime.MinValue.Ticks
protected

The last time a cache folder exceeded both the optimum and maximum limits for file count. If recent, indicates a misconfiguration; the subfolders="" count needs to be increased.

Definition at line 49 of file CleanupWorker.cs.

long ImageResizer.Plugins.DiskCache.CleanupWorker.lastWorked = DateTime.MinValue.Ticks
protected

The last time we did work (or attempted to do work, failing if the queue was empty)

Definition at line 65 of file CleanupWorker.cs.

bool ImageResizer.Plugins.DiskCache.CleanupWorker.otherProcessManagingCleanup = false
protected

When true, indicates that another process is managing cleanup operations - this thread is idle, waiting for the other process to end before it can pick up work.

Definition at line 74 of file CleanupWorker.cs.

Property Documentation

bool ImageResizer.Plugins.DiskCache.CleanupWorker.ExteralProcessCleaning
get

When true, indicates that another process is managing cleanup operations - this thread is idle, waiting for the other process to end before it can pick up work.

Definition at line 70 of file CleanupWorker.cs.


The documentation for this class was generated from the following file: