Skip to content

Commit ac5a402

Browse files
committed
Quick fix.
1 parent d055952 commit ac5a402

File tree

3 files changed

+199
-143
lines changed

3 files changed

+199
-143
lines changed

src/ImageSharp.Web/Middleware/ImageSharpMiddleware.cs

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@
2424

2525
namespace SixLabors.ImageSharp.Web.Middleware
2626
{
27+
public struct ImageResponse
28+
{
29+
internal ImageContext Context { get; set; }
30+
public ImageCacheMetadata Metadata { get; set; }
31+
public Stream Stream { get; set; }
32+
33+
}
34+
35+
public struct CacheImageResponse
36+
{
37+
public bool NewOrUppdated { get; set; }
38+
public ImageMetadata Metadata { get; set; }
39+
public ImageCacheMetadata CacheMetadata { get; set; }
40+
41+
public IImageCacheResolver Resolver { get; set; }
42+
43+
}
44+
45+
2746
/// <summary>
2847
/// Middleware for handling the processing of images via image requests.
2948
/// </summary>
@@ -32,14 +51,14 @@ public class ImageSharpMiddleware
3251
/// <summary>
3352
/// The write worker used for limiting identical requests.
3453
/// </summary>
35-
private static readonly ConcurrentDictionary<string, Lazy<Task>> WriteWorkers
36-
= new ConcurrentDictionary<string, Lazy<Task>>(StringComparer.OrdinalIgnoreCase);
54+
private static readonly ConcurrentDictionary<string, Lazy<Task<ImageResponse>>> WriteWorkers
55+
= new ConcurrentDictionary<string, Lazy<Task<ImageResponse>>>(StringComparer.OrdinalIgnoreCase);
3756

3857
/// <summary>
3958
/// The read worker used for limiting identical requests.
4059
/// </summary>
41-
private static readonly ConcurrentDictionary<string, Lazy<Task<ValueTuple<bool, ImageMetadata>>>> ReadWorkers
42-
= new ConcurrentDictionary<string, Lazy<Task<ValueTuple<bool, ImageMetadata>>>>(StringComparer.OrdinalIgnoreCase);
60+
private static readonly ConcurrentDictionary<string, Lazy<Task<CacheImageResponse>>> ReadWorkers
61+
= new ConcurrentDictionary<string, Lazy<Task<CacheImageResponse>>>(StringComparer.OrdinalIgnoreCase);
4362

4463
/// <summary>
4564
/// Used to temporarily store source metadata reads to reduce the overhead of cache lookups.
@@ -251,28 +270,31 @@ private async Task ProcessRequestAsync(
251270

252271
// Check the cache, if present, not out of date and not requiring and update
253272
// we'll simply serve the file from there.
254-
(bool newOrUpdated, ImageMetadata sourceImageMetadata) =
273+
var cacheImageResponse =
255274
await this.IsNewOrUpdatedAsync(sourceImageResolver, imageContext, key);
256275

257-
if (!newOrUpdated)
276+
if (!cacheImageResponse.NewOrUppdated)
258277
{
278+
await this.SendResponseAsync(imageContext, key, cacheImageResponse.CacheMetadata, null, cacheImageResponse.Resolver);
259279
return;
260280
}
261281

262-
// Not cached? Let's get it from the image resolver.
282+
var sourceImageMetadata = cacheImageResponse.Metadata;
283+
284+
// Not cached, or is updated? Let's get it from the image resolver.
263285
RecyclableMemoryStream outStream = null;
264286

265287
// Enter a write lock which locks writing and any reads for the same request.
266288
// This reduces the overheads of unnecessary processing plus avoids file locks.
267-
await WriteWorkers.GetOrAdd(
289+
var writeResult = await WriteWorkers.GetOrAdd(
268290
key,
269-
_ => new Lazy<Task>(
291+
_ => new Lazy<Task<ImageResponse>>(
270292
async () =>
271293
{
272294
try
273295
{
274296
// Prevent a second request from starting a read during write execution.
275-
if (ReadWorkers.TryGetValue(key, out Lazy<Task<(bool, ImageMetadata)>> readWork))
297+
if (ReadWorkers.TryGetValue(key, out Lazy<Task<CacheImageResponse>> readWork))
276298
{
277299
await readWork.Value;
278300
}
@@ -338,7 +360,27 @@ await WriteWorkers.GetOrAdd(
338360
// for the same key.
339361
CacheResolverLru.TryRemove(key);
340362

341-
await this.SendResponseAsync(imageContext, key, cachedImageMetadata, outStream, null);
363+
// This worker queue should be all about writing.
364+
// Not sending. sending would only happen once
365+
// when it is part of this queue.
366+
367+
var taskCompletionSource = new TaskCompletionSource<ImageResponse>();
368+
369+
370+
// Return the response to the pipeline so it can return the response to multiple callers.
371+
var result = new ImageResponse
372+
{
373+
Context = imageContext,
374+
Metadata = cachedImageMetadata,
375+
Stream = outStream
376+
};
377+
378+
return result;
379+
380+
// taskCompletionSource.SetResult(result);
381+
382+
// return taskCompletionSource.Task;
383+
342384
}
343385
catch (Exception ex)
344386
{
@@ -349,10 +391,13 @@ await WriteWorkers.GetOrAdd(
349391
}
350392
finally
351393
{
352-
await this.StreamDisposeAsync(outStream);
353-
WriteWorkers.TryRemove(key, out Lazy<Task> _);
394+
// await this.StreamDisposeAsync(outStream);
395+
WriteWorkers.TryRemove(key, out Lazy<Task<ImageResponse>> _);
354396
}
355397
}, LazyThreadSafetyMode.ExecutionAndPublication)).Value;
398+
399+
400+
await this.SendResponseAsync(imageContext, key, writeResult.Metadata, writeResult.Stream, null);
356401
}
357402

358403
private ValueTask StreamDisposeAsync(Stream stream)
@@ -377,24 +422,24 @@ private ValueTask StreamDisposeAsync(Stream stream)
377422
#endif
378423
}
379424

380-
private async Task<ValueTuple<bool, ImageMetadata>> IsNewOrUpdatedAsync(
425+
private async Task<CacheImageResponse> IsNewOrUpdatedAsync(
381426
IImageResolver sourceImageResolver,
382427
ImageContext imageContext,
383428
string key)
384429
{
385-
if (WriteWorkers.TryGetValue(key, out Lazy<Task> writeWork))
430+
if (WriteWorkers.TryGetValue(key, out Lazy<Task<ImageResponse>> writeWork))
386431
{
387432
await writeWork.Value;
388433
}
389434

390-
if (ReadWorkers.TryGetValue(key, out Lazy<Task<(bool, ImageMetadata)>> readWork))
435+
if (ReadWorkers.TryGetValue(key, out Lazy<Task<CacheImageResponse>> readWork))
391436
{
392437
return await readWork.Value;
393438
}
394439

395440
return await ReadWorkers.GetOrAdd(
396441
key,
397-
_ => new Lazy<Task<ValueTuple<bool, ImageMetadata>>>(
442+
_ => new Lazy<Task<CacheImageResponse>>(
398443
async () =>
399444
{
400445
try
@@ -426,7 +471,8 @@ private async Task<ValueTuple<bool, ImageMetadata>> IsNewOrUpdatedAsync(
426471
{
427472
// Remove the null resolver from the store.
428473
CacheResolverLru.TryRemove(key);
429-
return (true, sourceImageMetadata);
474+
475+
return new CacheImageResponse { NewOrUppdated = true, Metadata = sourceImageMetadata};
430476
}
431477

432478
// Has the cached image expired?
@@ -437,16 +483,25 @@ private async Task<ValueTuple<bool, ImageMetadata>> IsNewOrUpdatedAsync(
437483
{
438484
// We want to remove the resolver from the store so that the next check gets the updated file.
439485
CacheResolverLru.TryRemove(key);
440-
return (true, sourceImageMetadata);
486+
return new CacheImageResponse { NewOrUppdated = true, Metadata = sourceImageMetadata};
441487
}
442488

489+
// Likewise this queue should be about getting the image metadata
490+
// not
491+
443492
// We're pulling the image from the cache.
444-
await this.SendResponseAsync(imageContext, key, cachedImage.ImageCacheMetadata, null, cachedImage.ImageCacheResolver);
445-
return (false, sourceImageMetadata);
493+
// await this.SendResponseAsync(imageContext, key, cachedImage.ImageCacheMetadata, null, cachedImage.ImageCacheResolver);
494+
495+
// The image is cached. Return the cached image so multiple callers can write a response.
496+
return new CacheImageResponse {
497+
NewOrUppdated = false,
498+
Metadata = sourceImageMetadata,
499+
CacheMetadata = cachedImage.ImageCacheMetadata,
500+
Resolver = cachedImage.ImageCacheResolver};
446501
}
447502
finally
448503
{
449-
ReadWorkers.TryRemove(key, out Lazy<Task<(bool, ImageMetadata)>> _);
504+
ReadWorkers.TryRemove(key, out Lazy<Task<CacheImageResponse>> _);
450505
}
451506
}, LazyThreadSafetyMode.ExecutionAndPublication)).Value;
452507
}

0 commit comments

Comments
 (0)