May return either a physical file name or a MemoryStream with the data. Faster than GetCachedFile, as writes are (usually) asynchronous. If the write queue is full, the write is forced to be synchronous again. Identical to GetCachedFile() when asynchronous=false
108 if (lp.Logger != null) { sw =
new Stopwatch(); sw.Start(); }
111 bool hasModifiedDate = !sourceModifiedUtc.Equals(DateTime.MinValue);
115 if (hashModifiedDate && hasModifiedDate)
116 keyBasis +=
"|" + sourceModifiedUtc.Ticks.ToString(NumberFormatInfo.InvariantInfo);
119 string relativePath =
new UrlHasher().hash(keyBasis, subfolders,
"/") +
'.' + extension;
122 string physicalPath = PhysicalCachePath.TrimEnd(
'\\',
'/') + System.IO.Path.DirectorySeparatorChar +
123 relativePath.Replace(
'/', System.IO.Path.DirectorySeparatorChar);
126 CacheResult result =
new CacheResult(
CacheQueryResult.Hit, physicalPath, relativePath);
129 bool compareModifiedDates = hasModifiedDate && !hashModifiedDate;
131 bool asyncFailed =
false;
136 bool mayBeLocked = Locks.MayBeLocked(relativePath.ToUpperInvariant());
143 if (!TryWriteFile(result, physicalPath, relativePath, writeCallback, sourceModifiedUtc, timeoutMs, !mayBeLocked)) {
145 result.Result = CacheQueryResult.Failed;
148 else if ((!compareModifiedDates ? !
Index.existsCertain(relativePath, physicalPath) : !Index.modifiedDateMatchesCertainExists(sourceModifiedUtc, relativePath, physicalPath)) || mayBeLocked)
161 AsyncWrite t = CurrentWrites.Get(relativePath, sourceModifiedUtc);
163 if (t != null) result.Data = t.GetReadonlyStream();
170 (!compareModifiedDates ? !
Index.exists(relativePath, physicalPath) : !Index.modifiedDateMatches(sourceModifiedUtc, relativePath, physicalPath)))
173 result.Result = CacheQueryResult.Miss;
175 MemoryStream ms =
new MemoryStream(4096);
183 Stopwatch swio =
new Stopwatch();
187 if (!TryWriteFile(null, job.PhysicalPath, job.RelativePath, delegate(Stream s) { ((MemoryStream)job.
GetReadonlyStream()).WriteTo(s); }, job.ModifiedDateUtc, timeoutMs,
true)) {
190 if (lp.Logger != null)
191 lp.Logger.Warn(
"Failed to flush async write, timeout exceeded after {1}ms - {0}", result.RelativePath, swio.ElapsedMilliseconds);
195 if (lp.Logger != null)
196 lp.Logger.Trace(
"{0}ms: Async write started {1}ms after enqueue for {2}", swio.ElapsedMilliseconds.ToString().PadLeft(4), DateTime.UtcNow.Subtract(w.JobCreatedAt).Subtract(swio.Elapsed).TotalMilliseconds, result.RelativePath);
199 }
catch (Exception ex) {
200 if (lp.Logger != null) {
201 lp.Logger.Error(
"Failed to flush async write, {0} {1}\n{2}",ex.ToString(), result.RelativePath,ex.StackTrace);
204 CurrentWrites.Remove(job);
209 result.Data = w.GetReadonlyStream();
215 if (!TryWriteFile(result, physicalPath, relativePath, delegate(Stream s) { ms.WriteTo(s); }, sourceModifiedUtc, timeoutMs,
false)) {
216 if (lp.Logger != null)
217 lp.Logger.Warn(
"Failed to queue async write, also failed to lock for sync writing: {0}", result.RelativePath);
226 result.Result = CacheQueryResult.Failed;
230 if (lp.Logger != null) {
232 lp.Logger.Trace(
"{0}ms: {3}{1} for {2}, Key: {4}", sw.ElapsedMilliseconds.ToString(NumberFormatInfo.InvariantInfo).PadLeft(4), result.Result.ToString(), result.RelativePath, asynchronous ? (asyncFailed ?
"Fallback to sync " :
"Async ") :
"", keyBasis);
LockProvider QueueLocks
Provides string-based locking for image resizing (not writing, just processing). Prevents duplication...
bool TryExecute(string key, int timeoutMs, LockCallback success)
Attempts to execute the 'success' callback inside a lock based on 'key'. If successful, returns true. If the lock cannot be acquired within 'timoutMs', returns false In a worst-case scenario, it could take up to twice as long as 'timeoutMs' to return false.
MemoryStream GetReadonlyStream()
Wraps the data in a readonly MemoryStream so it can be accessed on another thread ...
AsyncWriteCollection CurrentWrites
Contains all the queued and in-progress writes to the cache.
CacheIndex Index
Provides an in-memory index of the cache.
bool Queue(AsyncWrite w, WriterDelegate writerDelegate)
Returns false when (a) the specified AsyncWrite value already exists, (b) the queue is full...
CacheResultHandler CacheResultReturned
Fired immediately before GetCachedFile return the result value.