improve image serving performance slightly

This commit is contained in:
Luke Pulverenti 2013-09-23 20:04:02 -04:00
parent bb281d4bcc
commit cbd767ddce
2 changed files with 67 additions and 42 deletions

View file

@ -121,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
} }
catch (IOException) catch (IOException)
{ {
// Cache file doesn't exist or is currently being written ro // Cache file doesn't exist or is currently being written to
} }
var semaphore = GetLock(cacheFilePath); var semaphore = GetLock(cacheFilePath);
@ -129,21 +129,24 @@ namespace MediaBrowser.Server.Implementations.Drawing
await semaphore.WaitAsync().ConfigureAwait(false); await semaphore.WaitAsync().ConfigureAwait(false);
// Check again in case of lock contention // Check again in case of lock contention
if (File.Exists(cacheFilePath)) try
{ {
try using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
return;
}
}
finally
{ {
await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
semaphore.Release(); semaphore.Release();
return;
} }
} }
catch (IOException)
{
// Cache file doesn't exist or is currently being written to
}
catch
{
semaphore.Release();
throw;
}
try try
{ {
@ -188,12 +191,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
var bytes = outputMemoryStream.ToArray(); var bytes = outputMemoryStream.ToArray();
var outputTask = toStream.WriteAsync(bytes, 0, bytes.Length); await toStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
// kick off a task to cache the result // kick off a task to cache the result
var cacheTask = CacheResizedImage(cacheFilePath, bytes); CacheResizedImage(cacheFilePath, bytes, semaphore);
await Task.WhenAll(outputTask, cacheTask).ConfigureAwait(false);
} }
} }
} }
@ -202,12 +203,51 @@ namespace MediaBrowser.Server.Implementations.Drawing
} }
} }
} }
finally catch
{ {
semaphore.Release(); semaphore.Release();
throw;
} }
} }
/// <summary>
/// Caches the resized image.
/// </summary>
/// <param name="cacheFilePath">The cache file path.</param>
/// <param name="bytes">The bytes.</param>
/// <param name="semaphore">The semaphore.</param>
private void CacheResizedImage(string cacheFilePath, byte[] bytes, SemaphoreSlim semaphore)
{
Task.Run(async () =>
{
try
{
var parentPath = Path.GetDirectoryName(cacheFilePath);
if (!Directory.Exists(parentPath))
{
Directory.CreateDirectory(parentPath);
}
// Save to the cache location
using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
// Save to the filestream
await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
}
}
catch (Exception ex)
{
_logger.ErrorException("Error writing to image cache file {0}", ex, cacheFilePath);
}
finally
{
semaphore.Release();
}
});
}
/// <summary> /// <summary>
/// Sets the color of the background. /// Sets the color of the background.
/// </summary> /// </summary>
@ -363,28 +403,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
return croppedImagePath; return croppedImagePath;
} }
/// <summary>
/// Caches the resized image.
/// </summary>
/// <param name="cacheFilePath">The cache file path.</param>
/// <param name="bytes">The bytes.</param>
private async Task CacheResizedImage(string cacheFilePath, byte[] bytes)
{
var parentPath = Path.GetDirectoryName(cacheFilePath);
if (!Directory.Exists(parentPath))
{
Directory.CreateDirectory(parentPath);
}
// Save to the cache location
using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
// Save to the filestream
await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
}
}
/// <summary> /// <summary>
/// Gets the cache file path based on a set of parameters /// Gets the cache file path based on a set of parameters
/// </summary> /// </summary>

View file

@ -314,6 +314,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <param name="context">The CTX.</param> /// <param name="context">The CTX.</param>
private async void ProcessHttpRequestAsync(HttpListenerContext context) private async void ProcessHttpRequestAsync(HttpListenerContext context)
{ {
var date = DateTime.Now;
LogHttpRequest(context); LogHttpRequest(context);
if (context.Request.IsWebSocketRequest) if (context.Request.IsWebSocketRequest)
@ -360,7 +362,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
var url = context.Request.Url.ToString(); var url = context.Request.Url.ToString();
var endPoint = context.Request.RemoteEndPoint; var endPoint = context.Request.RemoteEndPoint;
LogResponse(context, url, endPoint); var duration = DateTime.Now - date;
LogResponse(context, url, endPoint, duration);
} }
catch (Exception ex) catch (Exception ex)
@ -461,14 +465,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// <param name="ctx">The CTX.</param> /// <param name="ctx">The CTX.</param>
/// <param name="url">The URL.</param> /// <param name="url">The URL.</param>
/// <param name="endPoint">The end point.</param> /// <param name="endPoint">The end point.</param>
private void LogResponse(HttpListenerContext ctx, string url, IPEndPoint endPoint) /// <param name="duration">The duration.</param>
private void LogResponse(HttpListenerContext ctx, string url, IPEndPoint endPoint, TimeSpan duration)
{ {
if (!EnableHttpRequestLogging) if (!EnableHttpRequestLogging)
{ {
return; return;
} }
var statusode = ctx.Response.StatusCode; var statusCode = ctx.Response.StatusCode;
var log = new StringBuilder(); var log = new StringBuilder();
@ -476,7 +481,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k]))); log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k])));
var msg = "Http Response Sent (" + statusode + ") to " + endPoint; var responseTime = string.Format(". Response time: {0} ms", duration.TotalMilliseconds);
var msg = "Response code " + statusCode + " sent to " + endPoint + responseTime;
_logger.LogMultiline(msg, LogSeverity.Debug, log); _logger.LogMultiline(msg, LogSeverity.Debug, log);
} }